How do you invalidate a cache?
“Design the invalidation strategy for a product catalogue cache in front of Postgres. Cover TTL, explicit invalidation, stampedes and what "stale" is allowed to mean.”
What this tests
- Choosing between TTL, write-through, event-driven invalidation by staleness tolerance
- Cache stampede: locks, early recompute, jitter
- Consistency edge cases: race between DB write and cache set, delete-then-read
- Negative caching and hot keys
Answers by level
Read the beginner answer first and notice what is missing.
Start from the staleness budget. If marketing tolerates a price change appearing within a minute, TTL = 60 s with cache-aside is enough and simple. If a price must never be stale, the write path invalidates: update Postgres, then delete the cache key; the next read repopulates. Delete rather than set on write, because a set can race with a concurrent read that populates an older value. Keep a TTL anyway as a safety net for missed invalidations.
Stampedes: when a popular key expires, hundreds of requests miss simultaneously and all hit Postgres. Mitigations: a short lock so one request recomputes and the rest wait or serve the stale value; probabilistic early recompute so the key refreshes shortly before expiry; TTL jitter so keys created together do not expire together — the midnight expiry of every key set at midnight is the classic outage. Negative caching (cache "not found" briefly) stops a missing product id from hammering the database.
Hot keys: a single product on the homepage can saturate one Redis shard; an in-process cache with a few seconds TTL in front of Redis handles that, at the cost of per-instance staleness.
Green flags · Red flags
- Starts from a staleness budget, ideally per field group
- Delete-on-write with a safety TTL, and knows why delete beats set
- Names stampede defences: lock, early recompute, TTL jitter
- Mentions negative caching and hot keys
- Aware of the read-then-stale-set race and CDC as a fix
- "Just set a TTL and forget it."
- Sets the cache on write and does not see the race
- Gives every key the same TTL at the same time
- Cannot explain what happens when a hot key expires under load