Stale-While-Revalidate Cache (Go)
Topics: caching, background refresh, request coalescing, concurrency
Problem
Implement a stale-while-revalidate cache. Each entry is fresh for fresh, then stale
for a further stale window, then expired. The point: never block a caller on a refresh while a
usable value exists, and never stampede the origin (CDN/HTTP stale-while-revalidate).
func New[K comparable, V any](fresh, stale time.Duration, load func(K) V) *Cache[K, V]
func (c *Cache[K, V]) Get(key K) V
func (c *Cache[K, V]) Wait() // test helper: block until background refreshes finish
Get(key):
- fresh (within
fresh) → return the cached value; do not call load.
- stale (within the following
stale window) → return the stale value immediately, and
trigger one background refresh for that key (further stale gets while it runs do not start
another — dedup).
- expired / missing → call
load synchronously, store, and return it.
Key concepts
- Two deadlines per entry:
freshUntil = now+fresh, staleUntil = freshUntil+stale.
- Async revalidate: the stale path serves the old value and refreshes in a goroutine, so the
caller never waits.
- Dedup: a
refreshing set keyed by key ensures at most one in-flight refresh per key — the
thundering-herd guard.
sync.WaitGroup: tracks background refreshes so Wait can join them in tests.
The item type, New, store, and Wait are provided; you implement Get and refresh.
Run
go test -v -race ./challenges/stale-while-revalidate/go/
Sign in to submit your solution.