Page MenuHomePhabricator

Consider using 'Cache-Control: immutable' on versioned/long-cache load.php responses
Closed, ResolvedPublic

Description

Support landed in Firefox 49 (https://bugzilla.mozilla.org/show_bug.cgi?id=1267474).

In summary (from https://bitsup.blogspot.co.uk/2016/05/cache-control-immutable.html) the main benefit of "immutable" (compared to a high max-age) is that "immutable" is not bypassed when reloading a page.

Currently, regardless of max-age, browsers often ignore local cache expiry and perform If-None-Match/If-Modified-Since requests (yielding "304 Not Modified" responses for static assets). These are smaller than the "200 OK" response would have been (since browsers do remember and send E-Tag or Last-Modified headers), but are still worse than proper cache hits due to the required roundtrips for each 304 response.

Impact may be limited on Chrome since Chrome, unlike Firefox, does not ignore local cache expiry for subresources. When reloading a page in Chrome, cache-miss is only enforced on the main document. (per https://bugs.chromium.org/p/chromium/issues/detail?id=654378)

Background:

Event Timeline

Krinkle added a project: Performance-Team.
Krinkle moved this task from Inbox to Backlog on the MediaWiki-ResourceLoader board.
Krinkle renamed this task from Use 'Cache-Control: immutable' in versioned load.php response to Consider using 'Cache-Control: immutable' in versioned load.php response.Feb 9 2017, 10:22 PM
Krinkle moved this task from Backlog to Accepted Enhancement on the MediaWiki-ResourceLoader board.

Another write up from Mozilla, 1 year later:
https://hacks.mozilla.org/2017/01/using-immutable-caching-to-speed-up-the-web

And from Chromium:
https://blog.chromium.org/2017/01/reload-reloaded-faster-and-leaner-page_26.html

Facebook also wrote about it again in-depth. Also noting that, again, this mostly helps Firefox. Given that Chrome doesn't make these requests.
https://code.facebook.com/posts/557147474482256

Change 341483 had a related patch set uploaded (by krinkle):
[mediawiki/core] [WIP] resourceloader: Add 'Cache-control: immutable' to versioned responses

https://gerrit.wikimedia.org/r/341483

Once Chrome settled on a fix, we started engaging other browser vendors about the reload button behavior. We filed a bug with Firefox and they chose not to alter the long standing behavior of the reload button. Instead, Firefox implemented a proposal from one of our engineers to add a new cache-control header for some resources in order to tell the browser that this resource should never be revalidated.

As mentioned in various of the related bug reports and mailing lists, the proposed solution by Firefox is still suboptimal compared to Chrome's behaviour. Chrome only ignores cache for the main document (usually HTML) being reloaded, not the subresources. The subresources, after all, have valid cache expiry still. If they should be invalidated earlier, the natural way to do that is to either have shorter expiries, no-cache, or change the url if the resources are not meant to be compatible (e.g. version hash in path or query string).

Adding Cache-control: immutable would make Firefox no longer revalidate subresources with long expiries (> 30 days), but it would still needlessly revalidate the startup module and stylesheets, regardless of whether the intended expiry of 5-30min was reached. We can't add immutable to these responses.

Once Chrome settled on a fix, we started engaging other browser vendors about the reload button behavior. We filed a bug with Firefox and they chose not to alter the long standing behavior of the reload button. Instead, Firefox implemented a proposal from one of our engineers to add a new cache-control header for some resources in order to tell the browser that this resource should never be revalidated.

Safari has also been fixed to not revalidate unexpired subresources on reload, per https://bugs.webkit.org/show_bug.cgi?id=169756.

Change 341483 abandoned by Krinkle:
[WIP] resourceloader: Add 'Cache-control: immutable' to versioned responses

Reason:
Closing for now. See T149837 for more info. We may wanna reconsider this at some point (will leave the task open), but not actively being worked on. This patch could be re-used at that point.

https://gerrit.wikimedia.org/r/341483

Krinkle renamed this task from Consider using 'Cache-Control: immutable' in versioned load.php response to Consider using 'Cache-Control: immutable' on versioned/long-cache load.php responses.Sep 19 2019, 8:58 PM

Change 540963 had a related patch set uploaded (by Krinkle; owner: Krinkle):
[operations/mediawiki-config@master] static.php: Set "Cache-Control: immutable" on long-cache responses

https://gerrit.wikimedia.org/r/540963

Change 540963 merged by jenkins-bot:
[operations/mediawiki-config@master] static.php: Set "Cache-Control: immutable" on long-cache responses

https://gerrit.wikimedia.org/r/540963

Change 341483 restored by Krinkle:
[WIP] resourceloader: Add 'Cache-control: immutable' to versioned responses

https://gerrit.wikimedia.org/r/341483

Krinkle claimed this task.

My hesitation here stems from the fact that we've reduced our version hash size (ref T229245, and blog post), and we've drastically reduced the internal CDN expiry at WMF (from 30 days to 1 day, Wikitech docs), and we proactively invalidate client-side module storage every month (T229245).

All that to say: we really do really browsers to unconditionally and offline use module responses for 30 days as the Cache-Control max-age value declares. The only thing we're looking to gain from this task is to fix the Firefox behaviour where a reload also re-downloads static assets for no reason.

The thing is, Chrome and Safari have already treated that behaviour as a bug and fixed it. And setting immutable on all static resources has the side-effect of making the max-age ineffective. That is, we would no longer have the expectation that after the max-age expires, we get to renew the response based on unversioned changes. E.g. site configuration and other such things that we expect to propagate through ParserCache and client-side caches within a set period of time.

On top of that, the fact that we have the aforementioned client-side module storage (RL Architecture docs) means that we actually aren't affected by this issue much in the first place since we control our cache access directly within JS without relying on HTTP headers in the browser.

The exceptions are:

  • short-lived startup module where we similarly don't want Firefox to needlessly reload data, but we definitely can't put immutable on that 5-min expiry response.
  • static assets outside RL, such as site logos and such. These are outside the scope of this ResourceLoader, and I've already given those immutable via wmf-config/static.php (source).

As per the original task title - I'll close this resolved since we considered it, and applied it where it makes sense and is safe to do.

Change 341483 abandoned by Krinkle:

[mediawiki/core@master] [WIP] resourceloader: Add 'Cache-control: immutable' to versioned responses

Reason:

https://gerrit.wikimedia.org/r/341483