CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

testland/redis-cache-tests

Use when Redis is the app's cache and its behavior needs tests, or when choosing a cache invalidation strategy: TTLs, cache-aside write and invalidate, eviction under memory pressure, pub/sub invalidation across nodes and tenant key namespaces, plus stampede and stale-while-revalidate patterns.

Quality

84%

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

stampede.mdreferences/

Cache stampede (thundering herd) - phenomena and mitigations

A cache stampede ("dog-piling") occurs when a cached value expires under high load - many requesters simultaneously detect the miss, all recompute, all write back. Per en.wikipedia.org/wiki/Cache_stampede, the pathological state is "congestion collapse, preventing the resource from being recached and maintaining zero cache hit rates."

Symptoms in production

SignalInterpretation
DB / upstream latency spikes at cache-key TTL boundariesStampede on key expiry
Cache hit rate drops near zero, recovers slowlyCongestion collapse
Load spikes synchronised with cron / scheduled jobsMultiple processes invalidating + recomputing
Recompute-cost-vs-traffic ratio > 0.1Hot key - stampede risk

The three mitigation families

Per the Wikipedia article; full code, drawbacks, and the XFetch variable table are in stampede-mitigations.md.

  1. Locking - on miss, one process acquires a per-key lock and recomputes; others wait, return "not found," or serve stale. Risk: lock-holder crash leaves the cache empty for the lock TTL.
  2. External recomputation - a cron / near-expiry job refreshes known-hot keys off the request path. Doesn't help unknown or user-specific hot keys.
  3. Probabilistic early expiration (XFetch) - each reader refreshes early with rising probability as the value ages:
if (!value || (time() - delta * beta * log(rand(0,1))) >= expiry)
  recompute_and_cache(key)
else
  return value

Per Wikipedia, "setting beta=1 works well in practice." Measure delta (recompute cost) during refresh and store it beside value and expiry.

Choosing and combining

Choose by key knowability: XFetch for unknown / user-specific keys, external recompute for known-hot keys, locking as a backstop. The strongest setups layer them:

LayerStrategy
Cache backendTTL + stale-while-revalidate (stale-while-revalidate.md)
App logicXFetch on read for hot keys
OperationsExternal recompute for known-hot keys
Safety netDistributed lock (Redis SET NX EX)

Worked example

A homepage "top-10 products" aggregate under one key with ttl=300 expires at the traffic peak; ~1,200 concurrent misses hit the database and the hit rate collapses for ~40s. The key is known and hot, so external recomputation fits: a cron refreshes it every 240s, with XFetch on read as a backstop for a missed cron run. The load test below then asserts the upstream sees <=5 recomputes, down from ~1,000.

Testable behaviours

BehaviourTest
Lock holds under contentionN concurrent gets on a missing key → 1 recompute, N-1 wait/stale
XFetch probability rises near expiryStatistical: fraction refreshing early within target band
External recompute fires before TTLWrite source → wait → assert cache reflects new value
Stampede absent under loadN=1000 concurrent on cold key → upstream sees 1-5 recomputes

Anti-patterns

Anti-patternWhy it failsFix
No mitigation at allStampede inevitable under trafficPick at least one family
Lock without TTLLock-holder crash → deadlockTTL on locks
XFetch with very high beta (10+)Everyone refreshes constantlybeta=1; tune via load test
External recompute without monitoringFailed cron → stampedes return silentlyAlarm on cache-miss-rate spike
Hot key with must-revalidateForced revalidation = forced stampede at TTLSWR or grace mode
Mitigation tested only at low loadPasses at 10 RPS, fails at 1000Production-equivalent concurrency

Limitations

  • XFetch assumes exponentially distributed recompute cost; bimodal workloads should tune delta to p95, not mean.
  • Mitigations work per cache node; geo-distributed setups need per-region coordination, and TTL skew across nodes yields many node-local stampedes.

References

SKILL.md

tile.json