Part 11 · 1 chapters · ~11 min
Caching Across the System
Caches as replicas allowed to be stale: the layers from browser to database, cache-aside with delete-on-write, the invalidation race and its fixes, stampedes handled by coalescing, stale-while-revalidate and jitter, hot keys, and what must never be served from a cache.
20
Stale on purpose, fresh where it matters
code
// cache-aside with coalescing, stale-while-revalidate and jittered TTLs
const inflight = new Map<string, Promise<unknown>>();
async function cached<T>(key: string, load: () => Promise<T>, ttlS = 60, staleS = 300): Promise<T> {
const hit = await redis.get(key).then(v => v && JSON.parse(v) as { v: T; at: number });
const age = hit ? (Date.now() - hit.at) / 1000 : Infinity;
if (hit && age < ttlS) return hit.v; // fresh
const refresh = () => {
if (!inflight.has(key)) inflight.set(key, load().then(async v => {
const jitter = Math.floor(Math.random() * ttlS * 0.2);
await redis.set(key, JSON.stringify({ v, at: Date.now() }), 'EX', ttlS + staleS + jitter);
return v;
}).finally(() => inflight.delete(key)));
return inflight.get(key) as Promise<T>; // one load per key
};
if (hit && age < ttlS + staleS) { refresh().catch(() => {}); return hit.v; } // serve stale, refresh behind
return refresh();
}
// writes: database first, then delete the key
await db.update(product); await redis.del(`product:${product.id}`);the same ideas in the browser
TanStack Query's
staleTime, request deduplication and background refetch are this chapter in the client. HTTP's Cache-Control: max-age=60, stale-while-revalidate=300 does it at the CDN. The vocabulary is the same at every layer.CACHING ACROSS A DISTRIBUTED SYSTEM
cache-aside, invalidation, stampedes and the layers from browser to database
swipe the figure sideways, or tap expand for full screen
1/6
the layers
The layers: the browser cache and service worker (per user), the CDN (per region, shared), the BFF's in-process cache (per instance), a shared cache like Redis (per cluster), then the database. Each layer closer to the user is faster and harder to invalidate.