prevent-cache-stampede-with-single-flight
Use when a popular key expires and every request rebuilds it at once — collapse concurrent misses into one load with a lock, plus a stale-while-revalidate fallback.
- License 许可
- MIT
- 最近更新
- 2026-11-11
- Stars
- ★ 80
- Forks
- 17
01 前言 Front Matter
- name
- prevent-cache-stampede-with-single-flight
- description
- Use when a popular key expires and every request rebuilds it at once — collapse concurrent misses into one load with a lock, plus a stale-while-revalidate fallback.
02 资源文件 3
- 许可证LICENSE1.0 KB
- 参考文档SOURCE.md367 B
- 参考文档TRUST.auto.yaml2.2 KB
03 SKILL.md 正文
Prevent a cache stampede
When a hot key expires, every concurrent request misses and races to recompute it. A thousand callers recompute the same value and the origin takes a thousand hits — exactly the load the cache existed to prevent. Collapse the herd to a single loader.
Procedure
- Recognise the shape: an origin QPS spike that coincides with a key's TTL boundary, with p99 rising while the key is rebuilt.
- Single-flight in-process: coalesce concurrent loads for the same key into one. Go's
golang.org/x/sync/singleflight, Node'sp-memoize, or a per-key promise map:
inflight = {}
async def get(key):
if key not in inflight:
inflight[key] = asyncio.create_task(load(key))
return await inflight.pop(key)
- Across processes, take a short distributed lock before recomputing; losers wait briefly then re-read the now-populated key:
if redis.set(f"lock:{key}", 1, nx=True, ex=10):
val = load(key); redis.setex(key, 300, val)
else:
await asyncio.sleep(0.05); return await get(key)
- Prefer stale-while-revalidate over blocking: serve the expired value and refresh in the background, with
stale-if-errorcovering an origin outage. - Jitter every TTL so keys never expire together:
ttl = 300 + random.randint(0, 30). - Pre-warm the hottest keys on deploy or on a schedule, before the boundary rather than after it.
- Bound the wait: a crashed lock holder must release via the key's
exTTL, never via a manual unlock that can deadlock.
Pitfalls
- A lock with no TTL — a crashed holder blocks the key forever.
- Serving stale for a security-critical value (auth token, balance) where staleness is not acceptable.
- Single-flight keyed by a lossy key (
user) so unrelated tenants collide. - Refreshing in the background but never logging failures, so the stale value is served indefinitely.
- Collapsing the herd and still exceeding a rate-limited upstream's quota on the one reload.
- A per-process lock only, so N pods still produce N origin calls.
Verification
redis-cli monitor | grep -c "lock:" # one lock and one origin load per key
for i in $(seq 1 200); do curl -s localhost:8080/hot >/dev/null & done; wait
grep -c "origin_call" app.log # pass: ~1, not ~200
Report the collapse mechanism, the origin call count for N concurrent misses of a cold key, and the TTL jitter range used.
04 同仓库更多 Skills
recipe-performance
Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold/warm/background-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout/paint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.
mexc-spot-websocket
MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.
mexc-spot-rest
MEXC Spot REST workflows for public data, signed account requests, orders, wallet/admin actions, and secure signing without exposing API keys.
mexc-futures-websocket
MEXC Futures WebSocket workflows for public streams, private account/order/position streams, ping/pong, subscriptions, and depth maintenance.
0xklen-version-and-refresh-sanctions-lists
暂无简介
verify-tests-cover-changed-lines
Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.