Cache Invalidation
The Problem
When source data changes (e.g., user updates their profile), the cache still holds the old data. Cache invalidation removes stale entries to keep cache consistent with the database.
"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton
How It Works
1. Database changes → User updates profile
2. Application notifies cache → Invalidate "user:123"
3. Cache removes stale entry
4. Next read → Cache miss → Fetch from DB → Update cacheInvalidationManager
The InvalidationManager provides event-driven invalidation:
typescript
import { InvalidationManager } from "distributed-cache";
const invalidator = new InvalidationManager();
// Set TTL for a key (auto-expire after 60 seconds)
invalidator.setTTL("user:123", 60000);
// Check if key is still valid
const isValid = invalidator.checkTTL("user:123"); // true or false
// Manually invalidate a key
invalidator.invalidate("user:123");Event-Driven Invalidation
Subscribe to invalidation events:
typescript
import { InvalidationManager } from "distributed-cache";
const invalidator = new InvalidationManager();
// Subscribe to events
invalidator.subscribe((event) => {
console.log(`Cache invalidated: ${event.type} - ${event.key}`);
// Types: KEY_UPDATED, KEY_DELETED, KEY_EXPIRED
});
// When database changes
invalidator.onDatabaseChange({
type: "KEY_DELETED",
key: "user:123",
timestamp: Date.now(),
});Wildcard Invalidation
Invalidate multiple keys at once:
typescript
// Invalidate all user sessions
node.delete("session:user:1001");
node.delete("session:user:1002");
node.delete("session:user:1003");
// Or use pattern matching
const keys = node.getKeys();
keys
.filter((k) => k.startsWith("session:"))
.forEach((k) => node.delete(k));Integration with CacheNode
typescript
import { CacheNode } from "distributed-cache";
const node = new CacheNode("node-1", {
maxSize: 10000,
onEvicted: (key) => {
// Called when entry is evicted (LRU/LFU/FIFO)
console.log(`Entry evicted: ${key}`);
},
});
// Store with TTL
node.set("user:123", userData, 60000); // expires in 60s
// Manual invalidation
node.delete("user:123");
// Clear all entries
node.clear();Best Practices
| Practice | Why |
|---|---|
| Set TTL for all entries | Prevents stale data from lingering |
| Use event-driven invalidation | Real-time consistency with database |
| Invalidate on write-through | Update cache when DB changes |
| Batch invalidation | Reduce network overhead |
| Monitor hit rate | Low hit rate = too much invalidation |