The Ubiquitous Waste
200 users hit the uncached same key within the same instant:
naive: 200 identical db queries + 200 cache SETs
needed: ONE query; everyone shares the answer
this waste appears at EVERY layer:
- in-process: goroutines/threads duplicating fetches
- cross-pod: each pod independently missing the shared cache
- cross-region: every region refilling from origin
coalescing = the fix at whichever layer it hurts.
In-Process Coalescing (Singleflight)
Go's singleflight pattern — the canonical form:
calls for key K arrive concurrently:
first caller starts the actual fetch
others SUBSCRIBE to that flight's result channel
result lands → all callers receive the SAME value
var g singleflight.Group
v, err, shared := g.Do(key, func() (any, error) {
return db.Query(key)
})
semantics: per-key mutex on EXECUTION, broadcast on completion.
zero coordination infrastructure — pure process-local.
Cross-Pod Coalescing
pods can't share memory — coordinate through the cache store:
distributed lock variant:
SET fill:key pod-7 NX EX 3 ← one pod wins refill rights
winner: fetch + set + DEL lock
losers: poll cache briefly (50ms), then fall through to source
(bounded — never wait forever on a dead winner)
lease discipline matters:
- lock TTL short (3-5s) so crashes can't wedge the key
- losers' timeout bounded; worst case = old behavior (own fetch)
Where Each Level Applies
| Layer | Tool | Protects |
|---|---|---|
| Function call | singleflight | Duplicate work in one pod |
| Cache refill | fill locks / SWR | DB from herd (stampede lesson) |
| Expensive compute | job dedup table | Fare engine, PDF renders |
| Upstream APIs | request dedup window | Vendor rate limits |
compute example: fare quote service
quotes keyed by route+time-bucket;
singleflight collapses 50 simultaneous quote requests
into one pricing-engine call — vendor bill drops 98%.
The Subtle Costs
- LATENCY COUPLING: all subscribers wait for the slowest flight
(mitigation: leader does stale-if-error fallback on failure)
- THUNDERING COMPLETION: result broadcast wakes N waiters at once
(usually fine; huge N → stagger responses)
- KEY CANONICALIZATION required or flights fragment:
"?sort=price&color=red" vs "?color=red&sort=price" must agree
Combining With the Stampede Toolkit
full hot-key defense stack:
ttl jitter prevents synchronized expiry (prevention)
stale-while-revalidate serves old while refreshing (absorption)
SINGLEFLIGHT/FILL LOCKS guarantees one db query (guarantee)
L1 local caches spreads residual load across pods (dilution)
layers compose; each covers a failure mode of the previous.
Interview Framing
“1000 requests arrive for one cold key” expects: name the pattern (coalescing/singleflight), show both scopes (in-process AND distributed fill-lock with lease TTLs), note canonicalization as the practical gotcha. One sentence connecting it to stampede defenses shows you see the system, not the trick.
Premium Content
Unlock Request Coalescing and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans