CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/cache-coherence-patterns-reference

Pure-reference catalog of cache-coherence patterns across the request path. Defines the five-tier cache stack (browser → CDN → reverse-proxy → application → data store), the per-tier cache-writing patterns (cache-aside, write-through, write-back, write-around, refresh-ahead), and the canonical invalidation strategies (TTL-only, event-driven purge, surrogate keys, version-tagged URLs, soft purge), plus an anti-pattern table and a worked multi-tenant coherence-test example. Deep detail lives in references/: RFC 9111 Cache-Control / Vary / ETag directive tables, the cross-tier test surface, cache-stampede (thundering-herd) mitigations incl. the XFetch formula, and RFC 5861 stale-while-revalidate / stale-if-error semantics. Use for pattern selection, Cache-Control header design, coherence audits, stampede-refresh strategy, and SWR/SIE window design; use a cache-key-collision check when the question is whether two concrete requests collide on a key scheme.

80

Quality

100%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

stale-while-revalidate.mdreferences/

stale-while-revalidate and stale-if-error (RFC 5861)

stale-while-revalidate (SWR) and stale-if-error (SIE) are Cache-Control extensions defined in RFC 5861, widely implemented by browsers, CDNs (Cloudflare, Fastly, CloudFront), and reverse proxies (Varnish via grace).

DirectiveWhen stale-serve happensRevalidation
stale-while-revalidate=NUp to N seconds after max-age expiresBackground async; client sees stale
stale-if-error=NOrigin returns 5xx, up to N seconds after max-ageClient sees stale instead of the 5xx

stale-while-revalidate lifecycle

Per RFC 5861 §3: "caches MAY serve the response in which it appears after it becomes stale, up to the indicated number of seconds." Syntax: Cache-Control: max-age=60, stale-while-revalidate=300.

  1. t < max-age → fresh cache hit.
  2. max-age < t < max-age + SWR → stale served and one async revalidation fires - this is the stampede-mitigation property: only the first request revalidates, the herd coasts on stale (stampede.md).
  3. Revalidation succeeds → cache refreshed.
  4. t > max-age + SWR → truly stale; next request blocks on origin.

Failed-revalidation behaviour differs per vendor (Cloudflare keeps serving stale until the window expires; Fastly surfaces 5xx sooner; Varnish is VCL-configurable) - test the actual vendor.

stale-if-error

Per RFC 5861 §4: a stale response "MAY be used to satisfy the request, regardless of other freshness information" on origin 500/502/503/504. Composition:

Cache-Control: max-age=60, stale-while-revalidate=300, stale-if-error=86400

1-minute freshness, 5-minute background-refresh grace, 1-day serve-stale grace if the origin is down.

Interaction with must-revalidate

Per RFC 9111, must-revalidate forbids serving stale after expiry. It and SWR are mutually exclusive in spirit; most caches honour the strictest (must-revalidate wins). For SWR / SIE to work, don't add must-revalidate.

Per-vendor support

CacheSWRSIECaveat
CloudflareYesYesHonours response + request directives
FastlyYes (Surrogate-Control or Cache-Control)YesStale-on-error more aggressive
CloudFrontYes (since 2022)YesSIE needs origin error caching policy
Varnishgrace in VCLstale-if-errorSee varnish-test-vtc-syntax
nginxproxy_cache_use_stale updating... error timeoutDifferent keyword
BrowsersYesYesPer-tab behaviour varies; test
Service WorkersManual (Workbox SWR strategy)n/aCode-level implementation

Testable behaviours

BehaviourTest
SWR serves stale within windowmax-age=1, SWR=300; wait 5s; request → stale + async revalidate
SWR triggers exactly one revalidationOrigin sees one revalidate after the stale response returned
SWR window enforcedWait > max-age + SWR; next request blocks on origin
SIE serves stale on 5xxOrigin down; request within SIE window → 200 with stale data
SIE window enforcedOrigin down beyond window → user sees 5xx
must-revalidate wins over SWRBoth set → no stale served
Stampede mitigation under loadN=1000 concurrent at t=max-age+1s → origin sees 1-2 revalidates

Anti-patterns

Anti-patternWhy it failsFix
must-revalidate, stale-while-revalidate=300Contradictory; SWR silently ignoredDrop must-revalidate
SWR on private user data without privateStale exposure risksPair with private deliberately
SWR=0No grace; equivalent to omittingUse ≥30s
SWR window >> max-age (×10+)Stale for most of the lifetimeKeep proportionate
SIE without an origin-5xx alarm"Site looks fine" while origin is down for daysPair SIE with monitoring

Limitations

  • Async revalidation is best-effort; the stale entry can be evicted under memory pressure → blocking fetch.
  • Cold cache always blocks - SWR needs a previously cached response.
  • no-store overrides everything.
  • Staleness is invisible to users unless a Warning header survives (many CDNs strip it).

References

SKILL.md

tile.json