fix(cache): freshen the stored entry when a 304 extends its lifetime - #5700
Open
RaphaelFakhri wants to merge 1 commit into
Open
fix(cache): freshen the stored entry when a 304 extends its lifetime#5700RaphaelFakhri wants to merge 1 commit into
RaphaelFakhri wants to merge 1 commit into
Conversation
On the synchronous revalidation path CacheRevalidationHandler short-circuits on a 304 and never forwards it to the CacheHandler, so the merge logic that already exists there never runs. A 304 carrying a new Cache-Control was handled by deleting the entry instead, which means an origin extending freshness with `304 + Cache-Control: max-age=60`, the usual CDN behaviour, got no benefit at all: the next request was a full refetch, and the one after that revalidated again. RFC 9111 section 4.3.4 asks the cache to update the stored response from the validation response and recompute its freshness. When the 304 hands over a new lifetime, forward it to the CacheHandler so the existing 304 branch merges it into the stored entry, and serve the client the cached value from the interceptor as before. Everything the CacheHandler emits downstream in that case is dropped, since the client has already been served. A 304 whose Cache-Control does not grant a lifetime (no-cache, no-store) is left on the previous path and still evicts the entry.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5700 +/- ##
==========================================
- Coverage 93.47% 93.35% -0.12%
==========================================
Files 110 110
Lines 38846 38919 +73
==========================================
+ Hits 36310 36333 +23
- Misses 2536 2586 +50 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5505.
On the synchronous revalidation path
CacheRevalidationHandlershort-circuits on a 304 and never forwards it, so the RFC 9111 section 4.3.4 merge that already exists inCacheHandler's 304 branch only ever runs on the stale-while-revalidate background path. A 304 carrying a newCache-Controlwas handled by deleting the entry instead, so an origin extending freshness with304 + Cache-Control: max-age=60, which is what a CDN in front of an origin does, bought nothing: the next request was a full refetch and the one after that revalidated again.The interceptor's revalidation callback can now return true to ask for the validation response to be forwarded to the wrapped
CacheHandlerafter all. It does that only when the 304'sCache-Controlactually grants a new lifetime (max-ageors-maxage, and nono-cacheorno-store), serves the client the cached value itself as before, and gates everything theCacheHandleremits downstream so the client is served exactly once. A 304 whoseCache-Controldoes not grant a lifetime keeps the existing behaviour and still evicts the entry.Tests: one regression test in
test/interceptors/cache.jscovering max-age carried by a 304, verified to fail without the lib change. The conformance skip list is untouched: the304-etag-update-response-*cases need arbitrary stored headers to be merged from a 304 that carries no freshness information at all, which this change deliberately does not do.Local runs:
test/interceptors/cache.js88 pass,npm run test:cache-interceptor76 pass,npm run test:cache-testsidentical to main (276 tests, 218 passed, 0 failed, 54 failed-optional, 4 setup-failed),npm run lintclean.