Skip to content

cache: fix dispatch, stale retention and L1 freshness - #4394

Draft
larry-dalmeida wants to merge 10 commits into
larry-almeida-zse-cache-metrics-prfrom
larry-almeida-zse-cache-correctness-consolidation
Draft

larry-dalmeida wants to merge 10 commits into
larry-almeida-zse-cache-metrics-prfrom
larry-almeida-zse-cache-correctness-consolidation

Conversation

@larry-dalmeida

@larry-dalmeida larry-dalmeida commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

1. Fix Dispatch/coalescing & follower bodies: Singleflight normalization was missing; coalesced requests didn't properly share bodies, forcing multiple origin fetches for identical concurrent requests.

2. Fix Vary/304 handling: Variant isolation failed to prevent same-Vary entries from shadowing fresh variants; 304 responses discarded entity representation instead of preserving it.

3. Fix Stale-if-error & refresh retention: SIE didn't properly retain last-good responses when backend returned 500/502/503/504 or disconnected; failed refreshes were lost.

4. Fix Backend phase timeouts: Root Options timeout fields weren't wired into the cache filter's transport; configured budgets were ignored.

5. Fix Expired L1 shadowing fresh L2: L1 freshness gate checked !IsStale(), which was true for entries in the stale-while-revalidate window; this bypassed fresh shared L2 and forced unnecessary origin calls.

How to verify

Review the five commits in order:

Commit Purpose Verification
78a9bf85 Normalise origin dispatch and preserve follower bodies. Dispatch/body regression tests; coalescing requires one origin call for the synchronised burst.
d10650af Isolate Vary variants and preserve 304 representations. Vary/304 regression tests; the Vary-star oracle requires three origin calls.
b308eefa Retain last-good responses across failed refreshes. SIE covers 500/502/503/504, disconnect and expiry; queue saturation yields three drops and 257 successful conditional refreshes.
bdd9dc6b Honour backend phase timeouts for cache-origin fetches. Root cache_timeout_test.go checks option mapping, header-timeout stale preservation and recovery. These are phase budgets, not one end-to-end deadline.
cb8ac7e0 Consult shared L2 once L1 freshness expires. Two-process reproduction: normal and cache-only probes return fresh B/HIT, with zero extra origin calls. Workload evictions match absent cache-only probes.
Want to run it yourself?

Setup and complete replay commands

After the linked harness/prerequisite setup, run from the harness root ($PROM is the native Prometheus binary configured there):

SHA=cb8ac7e00d29bf8c578e5578dc57c462af6689ac
git clone --filter=blob:none --no-checkout https://github.com/zalando/skipper.git .runtime/skipper-lower
git -C .runtime/skipper-lower fetch origin "$SHA"
git -C .runtime/skipper-lower checkout --detach "$SHA"
python3 verify_l1_freshness.py --checkout .runtime/skipper-lower --sha "$SHA" --output .runtime/lower-l1
python3 verify_candidate_behaviour.py --l1-result .runtime/lower-l1/result.json --output .runtime/lower-coalescing
python3 verify_cache_remaining.py --checkout .runtime/skipper-lower --sha "$SHA" --mode correctness --prometheus-binary "$PROM" --output .runtime/lower-remaining

Screenshots

These panels illustrate the pressure/queue workload. Queries, hashes and capture provenance.

Cache evictions: 196 actual evictions matched 196 absent cache-only probes in the workload.

Panel 60: correctness-layer cache eviction rate

Refresh errors / dropped jobs: the workload independently observed three queue-overflow drops.

Panel 19: correctness-layer dropped refresh job rate

Refresh queue depth: reached the configured capacity of 256, then drained.

Correctness-layer refresh queue reaches 256 and drains

References & Additional Context

Share validated direct-versus-pipeline dispatch for cold misses and refreshes. Preserve transformed paths, outgoing Host and independent follower response bodies; reject Vary wildcard caching and sharing.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
Use variant-aware storage for cold misses, response processing and refreshes. Carry base keys through revalidation, enforce all Vary field lines for followers and retain cached bodies while merging conditional responses.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
Preserve eligible variants and original SIE timestamps on transport errors, incomplete bodies and HTTP 500/502/503/504, including inner loopback response processing. Recheck eligibility after fetch and skip queued refreshes superseded by newer fresh variants.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
Apply configured dial, TLS, response-header and expect-continue timeouts to the cache-origin transport without imposing a blanket request or body deadline. Cover timeout mapping, stale response preservation and recovery.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
Require positive-TTL L1 entries to remain within their freshness deadline before bypassing shared L2. Preserve zero-TTL semantics and stale retention, with freshness boundaries, fresh-L2 precedence, no-origin request regressions and benchmarks.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
@zalando-robot

Copy link
Copy Markdown

Docker image "registry-write.opensource.zalan.do/teapot/skipper:f17089f2ef5bab0e8ce46d2dfd23ed6049c817ec" is not based on an approved base image. Any production deployment relying on this image will be blocked.

To create a compliant Docker image of your application, you must reference an allowed Docker image as its base image in your Dockerfile. This base image must come from the Zalando Container Registry namespace library and use a recommended version as listed in the documentation.

@larry-dalmeida
larry-dalmeida force-pushed the larry-almeida-zse-cache-correctness-consolidation branch from f17089f to cb8ac7e Compare October 29, 2026 11:21
@zalando-robot

Copy link
Copy Markdown

Docker image "registry-write.opensource.zalan.do/teapot/skipper:cb8ac7e00d29bf8c578e5578dc57c462af6689ac" is not based on an approved base image. Any production deployment relying on this image will be blocked.

To create a compliant Docker image of your application, you must reference an allowed Docker image as its base image in your Dockerfile. This base image must come from the Zalando Container Registry namespace library and use a recommended version as listed in the documentation.

@larry-dalmeida larry-dalmeida changed the title Fix cache dispatch, stale retention and L1 freshness cache: fix dispatch, stale retention and L1 freshness Oct 29, 2026
Keep the singleflight callback independent of the live filter context after its initiating request returns. Cover cancellation during a blocked fetch and preserve the original Vary base key.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
@zalando-robot

Copy link
Copy Markdown

Docker image "registry-write.opensource.zalan.do/teapot/skipper:7f776e41eeb1e21b8ad0b275548473e127aca041" is not based on an approved base image. Any production deployment relying on this image will be blocked.

To create a compliant Docker image of your application, you must reference an allowed Docker image as its base image in your Dockerfile. This base image must come from the Zalando Container Registry namespace library and use a recommended version as listed in the documentation.

Snapshot filtered request headers at the cache boundary and use the owned identity for Vary followers, variant storage and queued refreshes, while preserving original-request loopback replay.

Cover rewritten Vary headers in RFC and dynamic-backend force mode, concurrent followers, warm hits and background refreshes.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
@zalando-robot

Copy link
Copy Markdown

Docker image "registry-write.opensource.zalan.do/teapot/skipper:2d787a53fbb78502dade261fa75fc8cbeee9591c" is not based on an approved base image. Any production deployment relying on this image will be blocked.

To create a compliant Docker image of your application, you must reference an allowed Docker image as its base image in your Dockerfile. This base image must come from the Zalando Container Registry namespace library and use a recommended version as listed in the documentation.

Distinguish L2 read errors from clean misses and retain eligible local responses only as stale-if-error candidates pending an origin failure. Preserve original response freshness and SIE metadata separately from the L1 warming deadline.

Cover transport and HTTP failures, fresh L2 precedence, clean misses, original SIE boundaries, queued refreshes and Vary isolation.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
@larry-dalmeida
larry-dalmeida force-pushed the larry-almeida-zse-cache-correctness-consolidation branch from bf309bc to f111f35 Compare October 30, 2026 15:00
Group dispatch, Vary, and stale-if-error coverage by the fix it protects. Drop repeated status grids, benchmarks, and the Contentful route-order contract tests.

Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>
@larry-dalmeida
larry-dalmeida force-pushed the larry-almeida-zse-cache-correctness-consolidation branch from d800aef to 4ce1e56 Compare October 30, 2026 16:06
Upstream docs should stay product-agnostic. CONTEXT.md glossary additions for cache tiers are out of scope for this PR.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Larry D Almeida <20266078+larry-dalmeida@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants