Problem/Motivation
In #2752961: No reliable method exists for clearing the Twig cache we're evaluating how to reliably clear the Twig cache upon deploying to production in a multi webheads environment. To achieve that, the proposed resolution involves rebuilding Drupal caches and invalidating all URLs with the rendered
cache tag if there's e.g. Varnish and/or a CDN in front.
Since Drupal 8 caches a lot more things than Drupal 7 and cache tags now allow changes to show up immediately on a site, even with Varnish or a CDN is in front (see the Purge API refactoring for D8), it's a shame we have to resort to such expensive operations when e.g. only a minor cosmetic change is made to a Twig template.
Proposed resolution
Upon deploying to production, we should find a less expensive way to only clear out what really needs to be cleared (e.g. render cache) and also make it easy for e.g. contrib to hook into Drupal and invalidate the rendered
tag (or any other tag that would make sense and ideally be less 'global') when a cache rebuild has been initiated.
Remaining tasks
Discuss and evaluate options.
User interface changes
None.
API changes
None anticipated.
Data model changes
None.
Comments
Comment #2
nielsvm CreditAttribution: nielsvm commentedIn my opinionated opinion, I see only one sustainable answer to the problem in question:
Clear all caches
" button.drush cr
command.drupal_rebuild
.I know that what I'm proposing sounds (and perhaps smells) pretty radical, but the truth of the matter is that many Drupalists continue to clear all caches upon every single deployment and it isn't even exceptional to see this being a standard part of continuous integration scripts. However, in real-life no single deployment is the same and many different kind of operations happen after a code deploy, for example:
drush fra
).Once the ability to destroy your sit.... clear all caches has been taken away, the individual actions (and also Drush commands and UI functionality) that lead to changes or to effects that require specific cache clears, then those code paths should do exactly that: clear the relevant tags. Sometimes this will be
rendered
but more often than not it will be more narrow than this.In a way the
purge
API is just an extension to core's caching system and as long as we're culturally acceptive of the fact that clearing all caches is a normal thing to do (its on t-shirts!), we'll continue to see sites going down for tiny deployments like template changes. Obviously I understand that it is pragmatic to do more wide-sweeping clearances (e.g. withrendered
) because it would otherwise be too complicated to accomplish, but that is still better than wiping out all caches at the same time.One intermediate scenario that I could think off is allowing to clear caches as long as
development.services.yml
is loaded, but not otherwise.Comment #3
Wim LeersWe can quite easily solve this: if we assign a cache tag to every
theme
hook, so that whenever the corresponding Twig template is modified (or added, in case it did not exist, or in case a more specific one is added), that cache tag is invalidated. But that's going to mean dozens more cache tags per HTML response. This is a hard requirement to do what you describe.Adding the and issue tags.
Indeed. But that's D9 material at best.
The problem is once again the same: dependencies, dependencies, dependencies. I've been talking about this for years: dependencies, dependencies, dependencies! Yes, it's annoying. But without it, we can't actually have a reliable system. There's a reason that modules and configuration specify dependencies. I was not involved with either of them. But on so many other levels, we're lacking dependency metadata.
Comment #4
Wim LeersClarifying issue title.
Comment #5
moshe weitzman CreditAttribution: moshe weitzman commented@wim - can you elaborate on the cache-tag-per-theme-hook idea? How would drupal learn that fivestar.whatever.twig has changed for a given deployment?
This problem isn't just limited to twig files. When Fivetar.php changes its code, then it can affect rendered output as well. Are we going to have cache tags for php files? I think most would say that this is too much. There is a risk here that curing this problem adds more complexity that its worth. Most people dont mind a cache clear when deploying a new footer.twig, for example.
Comment #6
Wim Leers#5: First: the Twig question.
We'd need a cache tag for the precise invocation + associated code. For example:
(from
\Drupal\comment\CommentLinkBuilder::buildCommentedEntityLinks()
)This would need a
twig:links__entity__comment__foo
cache tag that would be invalidated whenever:$settings['deployment_identifier']
changestwig.config.auto_reload
is enabled (ordebug
of course)I think this strategy would work for individual template changes.
Comment #7
Wim Leers#5 Now the general code question.
You're absolutely right, this would not be manageable. Not even remotely manageable. Because a code deployment change could lead for example to
being modified to
Result: 💥 — there's no way for us to know that suddenly there is a different cache tag at play for this particular page. This is impossible.
Comment #8
Wim LeersI could not agree more. Sorry for not making that more clear in #3.
Basically, this issue is about the following problem:
There are only two possible solutions:
Clearly, both approaches are mind-bogglingly onerous. Which is why I think this is not feasible. And indeed a cache clear is going to be the only feasible solution complexity-wise.
Comment #9
anavarre#3
Understood. With 16M HTTP headers across the stack (Apache, nginx, Varnish, and potentially an external CDN/reverse proxy) you can still sometimes get into 'too large HTTP headers' WSODs. So I agree that it'd be a hard requirement and would likely put users at even a greater risk of running into troubles, at least until #2241377: [meta] Profile/rationalise cache tags lands.
#8
Take this very plausible use case:
I understand it's a very complex problem to solve and there's not an immediate answer to doing things safely and easily, but if we put ourselves in the customer's shoes, this is not acceptable and makes cache tags moot for critical business operations.
Comment #10
dawehnerIts not only that, you don't even know easily which twig template changed. You'd need to know exactly the code before and after, this is so much more than what we do usually.
On top of that though this really just tackles template changes. There are all these other kind of changes, arbitrary changes in PHP code. There is no system how we can determine which code was involved to render a part of the page.
For me the solution is rather a different deployment/caching strategy, as in, use the old caches and then slowly build up the new ones.
Comment #11
Wim LeersYes.
stale-while-revalidate
: https://www.fastly.com/blog/stale-while-revalidate-stale-if-error-availa....BTW, the way companies like Facebook solve this, is by making users stick to a certain server (or in their case, server rack). They deploy to production all the time. But they roll it out in batches. And they ensure their data model only changes in an additive way, with the code handling the case of field X not yet being defined (fall back to default value, or "edit X" link). That way, the code version does not need to be in sync with the data schema/config schema version anymore.
Comment #12
dawehnerThis is super nice, thank you for the suggestion!
I would have expected datacenter :P
Comment #13
Wim Leers:D They're big, but not that big that each data center is only 1-2 percent of their users :P
Comment #14
anavarre#11
Wow, I didn't know about the
stale-while-revalidate
HTTP Cache-Control extension!https://tools.ietf.org/html/rfc5861 states that:
Looks, very, very promising and it would be the one thing that wouldn't turn me off when it comes to deploying and wiping caches like we're currently forced to do.
Unfortunately browser support is far from being a reality I'm afraid. To talk only about Chrome (since it has the most market share), they've stopped working on it ATM :-(
Comment #15
Wim Leers#14: the point is that you can use
stale-while-revalidate
inSurrogate-Control
to control your reverse proxies. This means you can deploy it today to make your infrastructure work more efficiently.Also being able to use this all the way to the client would be wonderful, but is not essential. With the client, you can work with a low
max-age
, to ensure speedy updates for clients.Comment #16
gg4 CreditAttribution: gg4 commentedDo we want to consider adding support for
stale-while-revalidate
orstale-if-error
statements toCache-Control
headers in the response from core?Comment #17
Wim LeersWe may want to consider adding support for it to the
page_cache
module. But let's not forget that on the wider web, pretty much only Fastly supports it out of the box.Comment #19
Ivan Berezhnov CreditAttribution: Ivan Berezhnov as a volunteer and at Drupal Ukraine Community for Levi9 commented