Cache Invalidation Patterns
title: "Cache Invalidation Patterns — Write-Through, Write-Behind, and TTL" description: "Cache invalidation patterns including TTL expiry, write-through, write-behind, and publish-subscribe ensure cached data stays fresh without excessive origin load." date: 2026-06-28 lastmod: 2026-06-28 weight: 21 tags: [apis, caching] }
Cache invalidation patterns determine how and when cached data is updated or removed after the underlying data changes, balancing freshness against cache efficiency.
What You'll Learn
- TTL-based invalidation
- Write-through, write-behind, write-around
- Publish-subscribe invalidation
Why It Matters
Cache invalidation is one of the hardest problems in computer science. The right pattern prevents stale data while maintaining high cache hit ratios.
Invalidation Patterns
flowchart LR
subgraph TTL
A[Set TTL] --> B[Auto-expire]
end
subgraph Write-Through
W[Write] --> C[Update DB] --> D[Update Cache]
end
subgraph Pub-Sub
E[Update DB] --> F[Publish Event] --> G[Invalidate Cache]
end
Code Examples
# TTL-based invalidation
@app.route('/api/products')
def get_products():
products = cache.get('products')
if not products:
products = db.get_products()
cache.setex('products', 300, json.dumps(products)) # 5 min TTL
return jsonify(products)
# Write-through cache
@app.route('/api/products', methods=['POST'])
def create_product():
data = request.json
product = db.insert('products', data)
# Update cache immediately
cache.set(f'product:{product.id}', json.dumps(product))
cache.delete('products') # Invalidate list
return jsonify(product), 201
# Write-behind cache
def update_product_batch(product_id, data):
# Write to cache immediately
cache.set(f'product:{product_id}', json.dumps(data))
# Queue DB update for later
update_queue.enqueue('update_product_db', product_id, data)
# Pub-sub invalidation with Redis
def invalidate_product(product_id):
# Publish invalidation event
r.publish('cache-invalidation', f'product:{product_id}')
# Subscriber process
def cache_subscriber():
pubsub = r.pubsub()
pubsub.subscribe('cache-invalidation')
for message in pubsub.listen():
if message['type'] == 'message':
key = message['data']
r.delete(key) # Remove from cache
Common Mistakes
1. No Invalidation Strategy
Stale data persists until TTL expires or is manually cleared.
2. Invalidating Too Aggressively
Invalidating on every read or too many keys reduces hit ratio.
3. Not Invalidating Related Cache Keys
When product list changes, individual product caches may still be stale.
4. Race Conditions in Write-Through
Multiple concurrent writes may produce inconsistent cache state.
5. No Grace Period for Stale Data
Serve stale data while background refresh happens (stale-while-revalidate).
Practice Questions
- What is the simplest cache invalidation strategy?
- How does write-through invalidation work?
- What problem does pub-sub invalidation solve?
- What is stale-while-revalidate?
- Why invalidate related cache keys?
Answers:
- TTL expiry — let data expire naturally after a fixed duration.
- Every write updates both database and cache atomically.
- Invalidating cache across multiple application instances.
- Serve stale data while asynchronously refreshing the cache.
- Changes to one item affect queries that aggregate or list items.
Challenge: Implement a complete cache invalidation system for an e-commerce API. Handle product updates, inventory changes, and related list caches.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro