75 lines
2.5 KiB
Markdown
75 lines
2.5 KiB
Markdown
# Cache Invalidation Patterns
|
|
|
|
## Event-Based: Invalidate on Data Changes
|
|
|
|
Use when: consistency critical, staleness unacceptable.
|
|
|
|
```typescript
|
|
async function createPost(data: { title: string; content: string; authorId: string }) {
|
|
const post = await prisma.post.create({ data });
|
|
|
|
await Promise.all([
|
|
redis.del(`posts:author:${data.authorId}`),
|
|
redis.del('posts:recent'),
|
|
redis.del('posts:popular'),
|
|
]);
|
|
|
|
return post;
|
|
}
|
|
```
|
|
|
|
## Time-Based: TTL-Driven Expiration
|
|
|
|
Use when: staleness acceptable for TTL duration, mutations infrequent.
|
|
|
|
```typescript
|
|
async function getRecentPosts() {
|
|
const cached = await redis.get('posts:recent');
|
|
if (cached) return JSON.parse(cached);
|
|
|
|
const posts = await prisma.post.findMany({
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 10,
|
|
});
|
|
|
|
await redis.setex('posts:recent', 300, JSON.stringify(posts));
|
|
return posts;
|
|
}
|
|
```
|
|
|
|
## Hybrid: TTL + Event-Based Invalidation
|
|
|
|
Use when: mutations trigger immediate invalidation, TTL provides safety net.
|
|
|
|
```typescript
|
|
async function updatePost(postId: string, data: { title?: string }) {
|
|
const post = await prisma.post.update({
|
|
where: { id: postId },
|
|
data,
|
|
});
|
|
await redis.del(`post:${postId}`);
|
|
return post;
|
|
}
|
|
|
|
async function getPost(postId: string) {
|
|
const cached = await redis.get(`post:${postId}`);
|
|
if (cached) return JSON.parse(cached);
|
|
|
|
const post = await prisma.post.findUnique({
|
|
where: { id: postId },
|
|
});
|
|
if (post) await redis.setex(`post:${postId}`, 600, JSON.stringify(post));
|
|
return post;
|
|
}
|
|
```
|
|
|
|
## Strategy Selection by Data Characteristics
|
|
|
|
| Characteristic | Approach |
|
|
| ------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
| Changes >1/min | Avoid caching or use 5-30s TTL; consider real-time updates; event-based invalidation for consistency |
|
|
| Changes rare (hours/days) | Use 5-60min TTL; event-based invalidation on mutations; warm cache on startup |
|
|
| Read/write ratio >10:1 | Strong cache candidate; cache-aside pattern; warm popular data in background |
|
|
| Read/write ratio <3:1 | Weak candidate; optimize queries instead; cache only if DB bottlenecked |
|
|
| Consistency required | Short TTL + event-based invalidation; cache-through/write-behind patterns; add versioning for atomic updates |
|