Expiration & Caching Patterns
⏱️ Expiration & Caching Patterns
node3-5 mentioned "Redis patterns" for caching without ever teaching them. This chapter is that deep dive: how keys expire on their own, the cache-aside pattern nearly every Redis-backed cache uses, and the well-documented failure mode — cache stampede — that catches teams who skip past it.
TTL & EXPIRE
Any key can be given a time to live — after which Redis deletes it automatically, with no manual cleanup code required.
SET ... EX 3600 sets the value and a 3600-second (1 hour) expiration in one command. TTL reports the remaining seconds. PERSIST removes the expiration entirely, making the key permanent again. Once a key's TTL reaches zero, Redis removes it on its own — no cron job, no scheduled cleanup.
The Cache-Aside Pattern
Cache-aside is the standard shape nearly every Redis cache follows: check Redis first; on a hit, return immediately; on a miss, query the real database, then store the result in Redis with a TTL so the next request hits the cache instead.
The database is only ever queried on a genuine miss — every subsequent call within the 300-second TTL is served entirely from Redis, at a fraction of the latency.
Cache Stampede Prevention
A popular key's TTL eventually expires — and if that key is being requested constantly, many concurrent requests can all miss the cache at the exact same moment, each one independently querying the database to repopulate it. This is a cache stampede (also called "thundering herd" or "dog-piling") — a real, well-documented production incident pattern where a single expiring cache key causes a sudden spike of duplicate load against the database.
No Stampede Protection vs. a Simple Lock
No Protection
100 concurrent requests all miss the cache at once → all 100 hit the database simultaneously to fetch the same thing.
Lock-Based Protection
Only the first request acquires a lock and queries the database; the other 99 wait briefly and then read the now-repopulated cache.
A Simple Lock Using SET NX
SET key value NX only succeeds if the key doesn't already exist — a lightweight mutex:
Only the request that successfully sets the lock key queries the database; every other concurrent request backs off and retries the cache shortly after, rather than all piling onto the database at once. Chapter 10's Lua-scripted approach makes this pattern fully atomic.
| Command | Purpose |
|---|---|
EXPIRE key seconds | Sets a TTL on an existing key |
SET key value EX seconds | Sets a value and a TTL in one command |
TTL key | Reports remaining seconds before expiration |
PERSIST key | Removes a key's expiration |
SET key value NX | Only sets if the key doesn't exist — the basis of a simple lock |
If many keys are all set with the exact same TTL at roughly the same time (e.g. a bulk cache-warming job), they tend to expire together — recreating stampede conditions across many keys at once rather than just one. Adding a small random amount ("jitter") to each key's TTL — e.g. 300 seconds plus a random 0–30 seconds — spreads expirations out over time, reducing the odds of many keys going stale simultaneously. This is a lightweight complement to locking, not a replacement for it.
💻 Coding Challenges
Challenge 1: Set a Session With Expiration
Write the redis-cli command to store a session token for user 55 that expires after 30 minutes, then the command to check how much time is left.
Goal: Practice the SET ... EX shorthand and TTL together.
Challenge 2: Trace a Cache-Aside Flow
Walk through what happens, step by step, for two back-to-back calls to getProduct(42) using this chapter's cache-aside example — assume the cache starts empty.
Goal: Practice tracing the hit/miss branches of the cache-aside pattern across multiple calls.
Challenge 3: Diagnose a Stampede
A popular product page's cache key expires, and the database sees a sudden 200-query spike within the same second. Diagnose what likely happened and propose a fix using this chapter's material.
Goal: Practice recognizing a cache stampede from its symptoms and applying the lock-based fix.
🎯 What's Next
The next chapter is Pub/Sub & Scaling Real-Time Apps — PUBLISH/SUBSCRIBE from first principles, deepening the WebSockets course's brief mention of a Redis pub/sub adapter (web-sockets1-7).