2024-04-19 11:38:03 +01:00
|
|
|
---
|
|
|
|
title: Wagtail & Caching
|
|
|
|
class: text-center
|
|
|
|
highlighter: shiki
|
|
|
|
transition: slide-left
|
2024-05-03 13:33:41 +01:00
|
|
|
monaco: false
|
2024-04-19 11:38:03 +01:00
|
|
|
mdc: true
|
|
|
|
themeConfig:
|
|
|
|
primary: '#2e1f5e'
|
|
|
|
---
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
# <logos-wagtail class="fill-white" /> + Caching = ❤️
|
2024-04-19 11:38:03 +01:00
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
## Jake Howard{.mt-5}
|
2024-04-19 11:38:03 +01:00
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
### Wagtail Space NL 2024{.mt-5}
|
|
|
|
|
|
|
|
<!--
|
|
|
|
- Here to talk about Caching with Wagtail
|
|
|
|
- Dramatically improve the performance of your site
|
|
|
|
- Sometimes, for very little effort
|
|
|
|
-->
|
|
|
|
|
|
|
|
---
|
|
|
|
layout: full
|
|
|
|
---
|
|
|
|
|
|
|
|
# `$ whoami`
|
|
|
|
|
|
|
|
<ul class="list-none! [&>li]:m-0! text-2xl mt-10">
|
|
|
|
<li><mdi-fire class="fill-white"/> Senior Systems Engineer @ Torchbox</li>
|
|
|
|
<li><logos-wagtail class="fill-white"/> Core, Security & Performance teams @ Wagtail</li>
|
|
|
|
<li><mdi-server-plus class="fill-white" /> I'm an avid self-hoster</li>
|
|
|
|
<li><mdi-robot-excited class="fill-white" /> I help students build robots in my "spare" time <small>(https://srobo.org)</small></li>
|
2024-04-19 11:38:03 +01:00
|
|
|
</ul>
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
<ul class="list-none! text-sm [&>li]:m-0! mt-10 text-xl">
|
2024-04-19 11:38:03 +01:00
|
|
|
<li><mdi-earth /> theorangeone.net</li>
|
|
|
|
<li><mdi-github /> @RealOrangeOne</li>
|
2024-05-07 23:18:13 +01:00
|
|
|
<li><mdi-twitter /> @RealOrangeOne</li>
|
2024-04-19 11:38:03 +01:00
|
|
|
<li><mdi-mastodon /> @jake@theorangeone.net</li>
|
|
|
|
</ul>
|
2024-04-19 17:46:32 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
|
|
|
|
<style>
|
|
|
|
.slidev-layout {
|
|
|
|
background-color: #e85537;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
<!--
|
|
|
|
- Hi
|
|
|
|
- I'm Jake
|
|
|
|
- Senior Systems Engineer at Torchbox
|
|
|
|
- I'm also on the security team, performance team, and as of 2 weeks ago the core team for Wagtail
|
|
|
|
- I exist in many places on the internet
|
|
|
|
-->
|
|
|
|
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
# Disclaimer{style="color: #fd5765;"}
|
2024-04-19 17:46:32 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Disclaimer: This isn't a general performance talk
|
|
|
|
- Optimising Python, Django and Wagtail are their own topics
|
|
|
|
- Caching can be a part of optimisation
|
|
|
|
- But it's not the only part
|
|
|
|
- It's not a replacement for proper benchmarking and investigations
|
|
|
|
-->
|
|
|
|
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
2024-06-09 15:01:51 +01:00
|
|
|
layout: section
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
|
|
|
|
|
|
|
# What _is_ caching?
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- What is caching?
|
|
|
|
- Caching lets your code remember things it's already done
|
|
|
|
- Reuse a value you've already done the work to calculate
|
|
|
|
- It's always slower to do something than nothing
|
|
|
|
- Caching comes in many different forms
|
|
|
|
- From storing a variable outside a loop
|
|
|
|
- To caching functions
|
|
|
|
- To caching entire pages with a CDN
|
|
|
|
- Mostly focusing on the higher end today
|
|
|
|
- The higher up the list you are, the more smaller processes you're caching
|
|
|
|
- And the more performance you can get
|
|
|
|
-->
|
|
|
|
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
|
|
|
layout: center
|
|
|
|
---
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
# Scale
|
|
|
|
|
|
|
|
<style>
|
|
|
|
@keyframes grow {
|
|
|
|
from {
|
2024-06-10 21:35:09 +01:00
|
|
|
font-size: 0.5rem;
|
2024-05-03 13:33:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
to {
|
|
|
|
font-size: 30rem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
animation-name: grow;
|
|
|
|
animation-duration: 30s;
|
|
|
|
animation-timing-function: linear;
|
|
|
|
animation-fill-mode: forwards;
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|
2024-04-19 17:46:32 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Caching may not seem needed at some scales
|
|
|
|
- Small sites will probably be _fine_ without it
|
|
|
|
- As your site grows, it becomes more important
|
|
|
|
- Crash under your own weight and success
|
|
|
|
- But, you may not notice you need it until it's already an issue
|
|
|
|
- What runs fine locally may not in production
|
|
|
|
- A problem with so many things at scale
|
|
|
|
- If a page gets popular, it'll soon meet with the hug of death
|
|
|
|
- Or even if it's not that popular, just shared around a bit
|
|
|
|
- Like the recently-discovered Mastodon issue
|
|
|
|
-->
|
|
|
|
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
2024-06-09 15:01:51 +01:00
|
|
|
layout: section
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
# <logos-wagtail class="fill-white"/> Caching <em>in Wagtail</em>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Now, back to Wagtail
|
|
|
|
- Let's talk about 2 techniques to help you out with caching
|
|
|
|
- Both are included in all maintained versions of Wagtail
|
|
|
|
- So you can use them right now!
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: section
|
|
|
|
---
|
|
|
|
|
|
|
|
## 1:
|
|
|
|
# Template Fragment Caching
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Template fragment caching
|
|
|
|
- New ish in 5.2
|
|
|
|
- Lots of complex words, but quite a simple concept
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
2024-06-11 09:44:18 +01:00
|
|
|
layout: image-right
|
2024-05-03 13:33:41 +01:00
|
|
|
image: https://d1nvwtjgmbo5v5.cloudfront.net/media/images/Screen_Shot_2015-05-14_at_09.01.5.2e16d0ba.fill-1200x996.png
|
|
|
|
backgroundSize: cover
|
2024-06-11 09:44:18 +01:00
|
|
|
class: p-0 m-0 bg-black
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
|
|
|
|
```html
|
|
|
|
<div class="one-half--medium one-third--large">
|
|
|
|
<div class="card card--link">
|
|
|
|
<a href="/developers/springload/made-wagtail/" class="project-image">
|
|
|
|
<img src="https://d1nvwtjgmbo5v5.cloudfront.net/media/images/Screen_Shot_2015-05-14_at_09.01.52.2e16d0ba.fill-680x564.png" alt="" title="">
|
|
|
|
</a>
|
|
|
|
<div class="project__links">
|
|
|
|
<a class="project__info" href="/developers/springload/made-wagtail/">
|
|
|
|
<span class="u-sr-only">Project info</span>
|
|
|
|
<svg class="i i--grey i--hover">
|
|
|
|
<use xlink:href="#i-info"></use>
|
|
|
|
</svg>
|
|
|
|
</a>
|
|
|
|
<a class="project__visit" href="http://madewithwagtail.org/" title="Project link" data-analytics="Project|Link click">
|
|
|
|
<span class="u-sr-only">Project link</span>
|
|
|
|
<svg class="i i--grey i--hover">
|
|
|
|
<use xlink:href="#i-visit"></use>
|
|
|
|
</svg>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<h4 class="project-title">
|
|
|
|
Made with Wagtail
|
|
|
|
</h4>
|
|
|
|
<p class="project-author">
|
|
|
|
<a href="/developers/springload/" title="View the company page of Springload">
|
|
|
|
Springload
|
|
|
|
</a>
|
|
|
|
</p>
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Most of what you build in Wagtail will come out as HTML
|
|
|
|
- Pages to be shown by the browser
|
|
|
|
- But may take lots of intensive actions to create it
|
|
|
|
- Complex lists / filters or suggestions
|
|
|
|
- Finding lots of renditions
|
|
|
|
- Rendering streamfield blocks etc
|
|
|
|
- These can all be optimised in many different ways
|
|
|
|
- The deeper down you go, the more complex and often less impactful those optimisations usually are
|
|
|
|
- Why not cache an entire chunk of template?
|
|
|
|
- With all of that complexity contained within it
|
|
|
|
- That's the thing people see (sort of)
|
|
|
|
-->
|
2024-04-19 17:46:32 +01:00
|
|
|
|
|
|
|
---
|
|
|
|
layout: cover
|
2024-05-03 13:33:41 +01:00
|
|
|
background: /website-homepage.png
|
2024-04-19 17:46:32 +01:00
|
|
|
---
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
## Example:
|
|
|
|
# My website
|
2024-06-10 21:35:09 +01:00
|
|
|
### https://theorangeone.net
|
2024-05-03 13:33:41 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- An example: My website
|
|
|
|
- Subtle self-promotion, I know
|
|
|
|
- It's a relatively simple blog
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: image
|
|
|
|
image: /website-posts.png
|
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
Here's a list of posts
|
|
|
|
- Each item has a lot to it
|
|
|
|
- Title
|
|
|
|
- Date
|
|
|
|
- An image (renditions or unsplash)
|
|
|
|
- Introduction text (automatically generated from page content)
|
|
|
|
- Tags
|
|
|
|
- Reading time / Word count
|
|
|
|
- These all come from a few different places in code
|
|
|
|
- Database fields
|
|
|
|
- Model properties
|
|
|
|
- Template tags
|
|
|
|
- It'd be nice to cache them all together as they are
|
|
|
|
- That's fragment caching!
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: none
|
|
|
|
---
|
|
|
|
|
|
|
|
````md magic-move
|
|
|
|
```html
|
|
|
|
{% load wagtailcore_tags util_tags %}
|
|
|
|
|
|
|
|
<article class="media listing-item">
|
|
|
|
<div class="columns">
|
|
|
|
<figure class="media-left column is-{{ show_listing_images|yesno:'3,1' }} image-column">
|
|
|
|
{% if page.list_image_url %}
|
|
|
|
<a href="{% pageurl page %}" class="image" title="{{ page.title }}">
|
|
|
|
<img src="{{ page.list_image_url }}" alt="{{ page.hero_image_alt }}" loading="lazy" decoding="async" referrerpolicy="no-referrer" />
|
|
|
|
</a>
|
|
|
|
{% endif %}
|
|
|
|
</figure>
|
|
|
|
<div class="media-content column">
|
|
|
|
<div>
|
|
|
|
{% if breadcrumbs %}
|
|
|
|
{% include "common/breadcrumbs.html" with parents=page.get_parent_pages %}
|
|
|
|
{% endif %}
|
|
|
|
<h2 class="title is-3">
|
|
|
|
<a href="{% pageurl page %}">{{ page.title }}</a>
|
|
|
|
</h2>
|
|
|
|
{% include "common/content-details.html" %}
|
|
|
|
<p>{{ page.summary }}</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</article>
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
```html {all|1-3,27|4-26|all}
|
2024-06-10 21:35:09 +01:00
|
|
|
{% load wagtailcore_tags wagtail_cache %}
|
2024-05-03 13:33:41 +01:00
|
|
|
|
|
|
|
{% wagtailpagecache FRAGMENT_CACHE_TTL "listing-item" breadcrumbs show_listing_images %}
|
|
|
|
<article class="media listing-item">
|
|
|
|
<div class="columns">
|
|
|
|
<figure class="media-left column is-{{ show_listing_images|yesno:'3,1' }} image-column">
|
|
|
|
{% if page.list_image_url %}
|
|
|
|
<a href="{% pageurl page %}" class="image" title="{{ page.title }}">
|
|
|
|
<img src="{{ page.list_image_url }}" alt="{{ page.hero_image_alt }}" loading="lazy" decoding="async" referrerpolicy="no-referrer" />
|
|
|
|
</a>
|
|
|
|
{% endif %}
|
|
|
|
</figure>
|
|
|
|
<div class="media-content column">
|
|
|
|
<div>
|
|
|
|
{% if breadcrumbs %}
|
|
|
|
{% include "common/breadcrumbs.html" with parents=page.get_parent_pages %}
|
|
|
|
{% endif %}
|
|
|
|
<h2 class="title is-3">
|
|
|
|
<a href="{% pageurl page %}">{{ page.title }}</a>
|
|
|
|
</h2>
|
|
|
|
{% include "common/content-details.html" %}
|
|
|
|
<p>{{ page.summary }}</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</article>
|
|
|
|
{% endwagtailpagecache %}
|
|
|
|
```
|
|
|
|
````
|
|
|
|
|
|
|
|
<style>
|
|
|
|
.slidev-page, .slidev-code-wrapper, .slidev-code {
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Let's look at the template
|
|
|
|
- I like to keep reusable components in separate files
|
|
|
|
- Makes them easier to work with
|
|
|
|
- And makes fragment caching much easier too
|
|
|
|
- This has no caching at all
|
|
|
|
- [click]Let's add some
|
|
|
|
- It's just 2 lines of change[click]
|
|
|
|
- The tag might look a bit weird
|
|
|
|
- It's not an inclusion or a filter
|
|
|
|
- It's a fully custom template tag
|
|
|
|
- A name: To uniquely identify this template fragment from others
|
|
|
|
- A TTL: To determine how long the cache is valid for
|
|
|
|
- Whatever variables the tag needs
|
|
|
|
- So if the variables change, the cache is automatically invalidated
|
|
|
|
- Don't show listing images? Different cache!
|
|
|
|
- [click]Put the HTML you want in the middle
|
|
|
|
- It's still a Django template, so calling tags etc is completely fine
|
|
|
|
- They'll be cached too
|
|
|
|
- [click]The template is in charge of caching itself
|
|
|
|
- Keep the complexities hidden, and in 1 place
|
|
|
|
-->
|
2024-05-03 13:33:41 +01:00
|
|
|
|
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: /website-search.png
|
2024-06-10 21:35:09 +01:00
|
|
|
class: text-right
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
# What about<br>search?
|
|
|
|
|
|
|
|
<!--
|
|
|
|
This is a component, it's used in a few different places
|
|
|
|
- There's a posts list, and a search
|
|
|
|
- But the UI for each item is the same
|
|
|
|
- It takes the same context: A page, and creates the same HTML
|
|
|
|
- If it looks the same, just on different pages, can I reuse it?
|
|
|
|
- Yes!
|
|
|
|
-->
|
2024-05-03 13:33:41 +01:00
|
|
|
|
|
|
|
---
|
|
|
|
layout: center
|
|
|
|
---
|
|
|
|
|
|
|
|
```html {3}
|
|
|
|
<section class="container">
|
|
|
|
{% for page in listing_pages %}
|
|
|
|
{% include "common/listing-item.html" %}
|
|
|
|
{% endfor %}
|
|
|
|
</section>
|
|
|
|
```
|
|
|
|
|
|
|
|
<style>
|
|
|
|
code {
|
|
|
|
font-size: 1.5rem !important;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Include the template somewhere else, and the cache gets reused
|
|
|
|
- So long as the right variables are available in context
|
|
|
|
- Shared components across your site can be accelerated
|
|
|
|
- As can entire sections like the navbar
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: image
|
|
|
|
image: /website-search.png
|
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Caching HTML blocks has a few nice benefits over caching the whole page
|
|
|
|
- Searches are still performed live, but the display of the results are cached
|
|
|
|
- Published pages appear immediately, without needing to invalidate a cache
|
|
|
|
-->
|
|
|
|
|
|
|
|
---
|
|
|
|
layout: full
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
# Updating cached content
|
2024-05-03 13:33:41 +01:00
|
|
|
|
|
|
|
<v-click>
|
|
|
|
|
|
|
|
```python
|
|
|
|
>>> BlogPostPage.objects.first().cache_key
|
|
|
|
```
|
|
|
|
|
|
|
|
</v-click>
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
<br />
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
<v-click>
|
|
|
|
|
|
|
|
```python
|
|
|
|
@property
|
|
|
|
def cache_key(self) -> str:
|
|
|
|
"""
|
|
|
|
A generic cache key to identify a page in its current state.
|
|
|
|
Should the page change, so will the key.
|
|
|
|
|
|
|
|
Customizations to the cache key should be made in :attr:`get_cache_key_components`.
|
|
|
|
"""
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
</v-click>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
code {
|
|
|
|
font-size: 1rem !important;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
If I change a page, I want the content to update
|
|
|
|
- How does it know when to regenerate the HTML?
|
|
|
|
- [click]`page.cache_key`
|
|
|
|
- Custom attribute on all your pages
|
|
|
|
- [click]You can use it for other things if you need it
|
|
|
|
- If a change is published, or the page is moved, the cache key changes, so the existing cache is ignored
|
|
|
|
- And the old cached item will eventually expire
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: center
|
|
|
|
---
|
|
|
|
|
|
|
|
# What about Django?
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
````md magic-move
|
2024-05-03 13:33:41 +01:00
|
|
|
```jinja
|
|
|
|
{% load cache %}
|
|
|
|
{% cache 500 sidebar request.user.username %}
|
|
|
|
.. sidebar for logged in user ..
|
|
|
|
{% endcache %}
|
|
|
|
```
|
2024-06-10 21:35:09 +01:00
|
|
|
|
|
|
|
```jinja
|
|
|
|
{% load wagtail_cache %}
|
|
|
|
{% wagtailcache 500 sidebar request.user.username %}
|
|
|
|
.. sidebar for logged in user ..
|
|
|
|
{% endwagtailcache %}
|
|
|
|
```
|
|
|
|
````
|
|
|
|
|
|
|
|
<v-click>
|
2024-05-03 13:33:41 +01:00
|
|
|
|
|
|
|
- Current page
|
|
|
|
- Current site
|
2024-06-10 21:35:09 +01:00
|
|
|
- Skip in preview
|
2024-05-03 13:33:41 +01:00
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
</v-click>
|
2024-05-03 13:33:41 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- This might sound familiar
|
|
|
|
- Django's `{% cache %}`?
|
|
|
|
- This isn't new, Django has had a cache tag for a very long time
|
|
|
|
- In fact, 2007
|
|
|
|
- But it's dangerous to use it with Wagtail unmodified
|
|
|
|
- Preview content can get cached
|
|
|
|
- Per-site settings cache the wrong value
|
|
|
|
- [click]It's only a few small changes to use Wagtail's
|
|
|
|
- [click]Which wraps this tag, but is aware of the current page and site automatically
|
|
|
|
- If you modify the page, the cache is automatically invalidated
|
|
|
|
-->
|
|
|
|
|
2024-05-03 13:33:41 +01:00
|
|
|
---
|
|
|
|
layout: section
|
|
|
|
---
|
|
|
|
|
|
|
|
## 2:
|
|
|
|
# Frontend Caching
|
2024-05-03 17:47:51 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Frontend caching
|
|
|
|
- You can spend ages optimising a request
|
|
|
|
- Caching common chunks of HTML
|
|
|
|
- But not handling the request at all is even better
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
U[User]
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U--->CDN
|
|
|
|
CDN-..->W
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- What if we put something in front of Wagtail to serve the requests instead
|
|
|
|
- A CDN (eg Cloudflare, CloudFront)
|
|
|
|
- They cache the page, and serve it themselves
|
|
|
|
- A CDN is generally helping you in 2 main ways:
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart TD
|
|
|
|
U1[🧑💻]
|
|
|
|
U2[🧑💻]
|
|
|
|
U3[🧑💻]
|
|
|
|
U4[🧑💻]
|
|
|
|
U5[🧑💻]
|
|
|
|
U6[🧑💻]
|
|
|
|
U7[🧑💻]
|
|
|
|
U8[🧑💻]
|
|
|
|
U9[🧑💻]
|
|
|
|
U10[🧑💻]
|
|
|
|
U11[🧑💻]
|
|
|
|
U12[🧑💻]
|
|
|
|
U13[🧑💻]
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U1--->CDN
|
|
|
|
U2--->CDN
|
|
|
|
U3--->CDN
|
|
|
|
U4--->CDN
|
|
|
|
U5--->CDN
|
|
|
|
U6--->CDN
|
|
|
|
U7--->CDN
|
|
|
|
U8--->CDN
|
|
|
|
U9--->CDN
|
|
|
|
U10--->CDN
|
|
|
|
U11--->CDN
|
|
|
|
U12--->CDN
|
|
|
|
U13--->CDN
|
|
|
|
CDN-...->W
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
Serve a static copy of your website, so your servers aren't processing every request
|
|
|
|
- Handle many more requests concurrently
|
|
|
|
- Cloudflare handles 50 million requests per second globally (on average)
|
|
|
|
- Your servers can't
|
|
|
|
- Handle more traffic with fewer servers
|
|
|
|
- Imagine it like converting your site to be static
|
|
|
|
- 0 Database requests
|
|
|
|
- 0 templates used
|
|
|
|
- 0 cache hits
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: image
|
|
|
|
image: https://www.cloudflare.com/network-maps/cloudflare-pops-2O04nulSdNrRpJR9fs9OKv.svg
|
2024-06-10 21:35:09 +01:00
|
|
|
class: bg-white
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Store said cached copy closer to your users
|
|
|
|
- Reduced latency
|
|
|
|
- Makes your site seem faster
|
|
|
|
- Even helps on your Google Lighthouse scores
|
|
|
|
- Both of these are things you'll want as your website scales
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: /wagtail-homepage.png
|
|
|
|
---
|
|
|
|
|
2024-06-09 15:01:51 +01:00
|
|
|
## Example
|
2024-06-10 21:35:09 +01:00
|
|
|
# https://wagtail.org
|
2024-06-09 15:01:51 +01:00
|
|
|
|
|
|
|
<style>
|
|
|
|
code {
|
|
|
|
background-color: transparent !important;
|
|
|
|
}
|
|
|
|
</style>
|
2024-05-03 17:47:51 +01:00
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Let's look at an example: Wagtail.org
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: image
|
|
|
|
image: /map.jpg
|
|
|
|
transition: fade
|
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Wagtail.org is hosted in Dublin, Ireland (AWS `eu-west-1`)
|
|
|
|
- But I'm in Arnhem
|
|
|
|
-->
|
|
|
|
|
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: /map.jpg
|
|
|
|
transition: fade
|
|
|
|
---
|
|
|
|
## Arnhem → Ireland
|
|
|
|
# ~XXms
|
|
|
|
|
|
|
|
<style>
|
|
|
|
h1 {
|
|
|
|
font-size: 4rem;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
- XXms away
|
|
|
|
- But responses are being served quickly
|
|
|
|
- That's the CDN (Cloudflare, in our case)
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: /map.jpg
|
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
## Arnhem → XXX
|
2024-05-03 17:47:51 +01:00
|
|
|
# ~XXms
|
|
|
|
|
|
|
|
<style>
|
|
|
|
h1 {
|
|
|
|
font-size: 4rem;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- This was actually served from XXX
|
|
|
|
- Just XXms to get a response
|
|
|
|
- Quicker
|
|
|
|
- Closer to us
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
U[User]
|
|
|
|
|
|
|
|
subgraph Content Delivery Network
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
C[(Cache)]
|
|
|
|
end
|
|
|
|
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U---->CDN
|
|
|
|
CDN-.->C
|
|
|
|
C---->W
|
|
|
|
C-.->CDN
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
Let's cache our content!
|
|
|
|
- Put a caching layer between users and the site
|
|
|
|
- Requests are sent via cache
|
|
|
|
- Usually just adding a DNS record
|
|
|
|
- It's always DNS
|
|
|
|
- Ensure the CDN knows how long to cache pages for
|
|
|
|
- Cache headers
|
|
|
|
- Configuration in the CDN itself
|
|
|
|
- There's another talk about this
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
U[User]
|
|
|
|
A[Admin]
|
|
|
|
|
|
|
|
subgraph Content Delivery Network
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
C[(Cache)]
|
|
|
|
end
|
|
|
|
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U---->CDN
|
|
|
|
CDN-.->C
|
|
|
|
C---->W
|
|
|
|
C-.->CDN
|
|
|
|
|
|
|
|
A---->CDN
|
|
|
|
CDN---->W
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Make sure you skip caching authenticated requests (ie the admin)
|
|
|
|
- These pages are dynamic based on who is viewing them, so we can't cache them easily
|
|
|
|
- Wagtail does its best to make sure the admin is fast anyway
|
|
|
|
- May need to include the session id as part of the cache key
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
2024-06-09 15:01:51 +01:00
|
|
|
layout: section
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
|
|
|
|
# Content is cached!
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
U1[User]
|
|
|
|
U2[User]
|
|
|
|
U3[User]
|
|
|
|
|
|
|
|
subgraph Content Delivery Network
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
C[(Cache)]
|
|
|
|
end
|
|
|
|
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U1===>CDN
|
|
|
|
U2===>CDN
|
|
|
|
U3===>CDN
|
|
|
|
CDN==>C
|
|
|
|
C==>CDN
|
|
|
|
C-.....->W
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Content is now cached
|
|
|
|
- Pages load much faster
|
|
|
|
- Server load should drop drastically
|
|
|
|
- Might even be able to scale down
|
|
|
|
- Wagtail.org serves ~70% of all page loads from the CDN
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: image
|
|
|
|
image: /wagtail-homepage-typo.png
|
2024-06-10 21:35:09 +01:00
|
|
|
transition: fade
|
|
|
|
---
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Uh oh, there's a typo on one of the pages, better update it
|
|
|
|
- Easy, just publish an update to the page
|
|
|
|
- A quick visit to the admin makes that a breeze
|
|
|
|
- The cache still has the old content
|
|
|
|
- Users see the incorrect content
|
|
|
|
- But how does the CDN know the content has changed?
|
|
|
|
-->
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: /wagtail-homepage-typo.png
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
# It doesn't*
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Simple: It doesn't!
|
|
|
|
- The whole point of it is it doesn't need to hit Wagtail for every request
|
|
|
|
- So it can't know
|
|
|
|
- The cache will expire _eventually_
|
|
|
|
- What if it needs to go out sooner
|
|
|
|
- What if it's more serious than just a typo
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: section
|
|
|
|
---
|
|
|
|
|
|
|
|
## Solution:
|
|
|
|
# Frontend Cache Invalidation
|
|
|
|
### Wagtail secret sauce <logos-wagtail class="fill-white"/>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Frontend cache invalidation!
|
|
|
|
- Wagtail to the rescue
|
|
|
|
- Some magic Wagtail sauce
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
U[User]
|
|
|
|
|
|
|
|
subgraph Content Delivery Network
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
C[(Cache)]
|
|
|
|
end
|
|
|
|
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
|
|
|
U--->CDN
|
|
|
|
CDN-->C
|
|
|
|
C-->CDN
|
2024-06-09 15:01:51 +01:00
|
|
|
C--->W
|
2024-05-03 17:47:51 +01:00
|
|
|
|
|
|
|
W-.->|Frontend Cache Invalidation|CDN
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Tighter integrations between Wagtail and the CDN
|
|
|
|
- Allows Wagtail to instruct the CDN to clear its cache for a given page
|
|
|
|
- Purging the cache much quicker
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: center
|
|
|
|
---
|
|
|
|
|
|
|
|
# `settings.py`
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
|
|
|
|
<v-click>
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
### 1.
|
|
|
|
|
|
|
|
```python {3}
|
|
|
|
INSTALLED_APPS = [
|
|
|
|
...
|
|
|
|
"wagtail.contrib.frontend_cache"
|
|
|
|
]
|
|
|
|
```
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
</v-click>
|
|
|
|
|
|
|
|
<v-click>
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
#### 2.
|
|
|
|
|
|
|
|
```python
|
|
|
|
WAGTAILFRONTENDCACHE = {
|
|
|
|
'cloudflare': {
|
|
|
|
'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend',
|
|
|
|
'BEARER_TOKEN': os.environ["CF_BEARER_TOKEN"],
|
|
|
|
'ZONEID': os.environ["CF_ZONE_ID"],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
</v-click>
|
|
|
|
<v-click>
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
#### 3. ???
|
|
|
|
|
|
|
|
#### 4. Profit!
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
</v-click>
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
<style>
|
|
|
|
code {
|
|
|
|
font-size: 0.9rem !important;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- Integrating is simple
|
|
|
|
- [click]Add entry to `INSTALLED_APPS`
|
|
|
|
- [click]dd credentials and configuration
|
|
|
|
- Wagtail supports quite a few backends!
|
|
|
|
- [click]That's it!
|
|
|
|
- All the hooks into all the right places are set up for you!
|
|
|
|
- You can customize this as you need for listing pages / custom configuration etc
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: fact
|
|
|
|
---
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
flowchart LR
|
|
|
|
A[Admin]
|
|
|
|
|
|
|
|
subgraph Content Delivery Network
|
|
|
|
CDN{Content<br>Delivery Network}
|
|
|
|
C[(Cache)]
|
|
|
|
end
|
|
|
|
|
|
|
|
W[(Wagtail)]
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
A-->|Publish new content to<br>blog post 1|W
|
2024-05-03 17:47:51 +01:00
|
|
|
|
|
|
|
W-.->|<code>PURGE /blog/post-1</code>|CDN
|
|
|
|
|
|
|
|
CDN-.->C
|
|
|
|
```
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- When you publish a page, it'll automatically be purged
|
|
|
|
- It can take a minute or so, depending on your CDN
|
|
|
|
- Usually much faster than that
|
|
|
|
- Then when a user loads the page, it's cached, and subsequent loads go back to being lightning fast
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
background: https://d1nvwtjgmbo5v5.cloudfront.net/media/images/Screen_Shot_2015-05-14_at_09.01.5.2e16d0ba.fill-1200x996.png
|
|
|
|
---
|
|
|
|
|
|
|
|
# Conclusion
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- When most people think of "performance", they tend to think "database queries"
|
|
|
|
- Which is true, that's where a lot of time goes
|
|
|
|
- But there's more to optimising a site than sprinkling `select_related` / `prefetch_related`
|
|
|
|
- It's faster to do less than to do more
|
|
|
|
- It's faster still to do nothing than something
|
|
|
|
- The higher up the stack your cache is, the more impactful it can be
|
|
|
|
- More of your code is cached
|
|
|
|
- But a slow page is still a slow page, even if it's not called as often
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: cover
|
|
|
|
---
|
|
|
|
|
|
|
|
# Performance means:
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
<Transform :scale="1.5">
|
|
|
|
|
|
|
|
<v-clicks>
|
2024-05-03 17:47:51 +01:00
|
|
|
|
|
|
|
- Users are happier <mdi-emoticon-happy />
|
|
|
|
- Servers are happier <mdi-server-network />
|
|
|
|
- The planet is happier <mdi-earth class="text-green" />
|
|
|
|
|
2024-06-10 21:35:09 +01:00
|
|
|
</v-clicks>
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
</Transform>
|
|
|
|
|
2024-06-11 09:44:18 +01:00
|
|
|
<!--
|
|
|
|
- So why repeat yourself? Make things faster!
|
|
|
|
- [click]Users are happier
|
|
|
|
- [click]Servers are happier
|
|
|
|
- [click]The planet is happier.
|
|
|
|
-->
|
|
|
|
|
2024-05-03 17:47:51 +01:00
|
|
|
---
|
|
|
|
layout: end
|
|
|
|
---
|
2024-05-07 23:18:13 +01:00
|
|
|
|
|
|
|
END
|