What you'll learn
A cache is a deliberate consistency trade, not free speed. Implement cache-aside with explicit keys and TTLs, invalidate writes, prevent stampedes, and measure whether Redis improves the system.
By the end of this lesson, you'll be able to:
- Implement cache-aside reads
- Choose keys and TTLs
- Invalidate after writes
- Observe hits, misses, latency, and failure
Core mental model
Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.
| Concept | What it means | Decision rule |
|---|---|---|
| Cache-aside | The application stores missing values | Use when the database remains authoritative |
| TTL | Maximum cache lifetime | Base it on acceptable staleness and recovery |
| Stampede | Many misses recompute one value | Coalesce work or use a short expiring lock |
Professional workflow
Build and verify Node.js programs from the terminal in small, observable steps.
- Define the cache boundary boundary: inputs, outputs, invariants, ownership, and expected failures.
- Design the data or message contract before choosing implementation details.
- Implement the smallest correct path with dependencies passed explicitly.
- Add validation, failure translation, cleanup, and concurrency behavior.
- Verify the boundary with realistic data and at least one adversarial case.
- Measure or observe the behavior before optimizing or extracting abstractions.
Keep the feedback loop short
Guided code lab
Read through Redis
The key is versioned, expiry explicit, and a miss falls back to the repository.
export async function getTask(id) {
const key = 'task:v1:' + id;
const hit = await redis.get(key);
if (hit) return JSON.parse(hit);
const task = await tasks.findById(id);
if (task) await redis.set(key, JSON.stringify(task), { EX: 60 });
return task;
}Invalidate after truth changes
Commit to the database first, then remove stale derived data.
const updated = await tasks.update(id, ownerId, patch);
await redis.del('task:v1:' + id);
return updated;Production practice
Contract
The database owns correctness; cache failure may reduce performance but must not corrupt authoritative data.
Verification
Test hit, miss, expiry, invalidation, corrupt JSON, Redis outage, concurrent misses, and tenant key isolation.
Operations
Set memory policy and TTLs, add jitter, track hit rate and latency, bound values, and keep bypass safe.
Common failure mode
Independent workshop
Add a measured Redis cache to task detail and owner summary reads.
Your finished workshop must include:
- Versioned tenant-safe keys
- Cache-aside helper
- TTL with jitter
- Post-write invalidation
- Outage fallback
- Metrics
Definition of done
Recap & quick check
Key takeaways
- Caches trade freshness for latency
- Database remains authoritative
- Every cache expires
- Writes need invalidation
- Measure benefit
Quick check
1. What is authoritative in cache-aside?
2. When should invalidation follow an update?
3. What reduces a stampede?
Next: Phase Project: Data-Backed Task API