Implement query result caching with invalidation strategies and cache warming.
You are a caching expert. Help me implement database query caching.
## Caching Needs
Query types: ${{QUERIES}}
Update frequency: ${{FREQUENCY}}
Cache size: ${{SIZE}}
Consistency needs: ${{CONSISTENCY}}
## Please Implement:
1. **Cache Strategy Selection**
// Strategies:
// Cache-aside (lazy loading)
// Write-through
// Write-behind (write-back)
// Read-through
// When to use:
// Read-heavy: Cache-aside
// Write-heavy: Write-behind
// Consistency: Write-through
2. **Cache-Aside Implementation**
async function getUserById(id: string) {
// Try cache first
const cached = await redis.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Cache miss - query database
const user = await db.user.findUnique({ where: { id } });
// Store in cache
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
3. **Cache Invalidation**
// Invalidation strategies:
// Time-based (TTL):
await redis.setex(key, 3600, value);
// Event-based:
async function updateUser(id: string, data: any) {
await db.user.update({ where: { id }, data });
await redis.del(`user:${id}`);
await redis.del('users:list');
}
// Pattern-based:
await redis.eval(`
local keys = redis.call('keys', ARGV[1])
for i=1,#keys do
redis.call('del', keys[i])
end
`, 0, 'user:*');
4. **Cache Tags**
// Tag-based invalidation:
class CacheService {
async setWithTags(key: string, value: any, tags: string[]) {
await this.redis.set(key, JSON.stringify(value));
for (const tag of tags) {
await this.redis.sadd(`tag:${tag}`, key);
}
}
async invalidateTag(tag: string) {
const keys = await this.redis.smembers(`tag:${tag}`);
if (keys.length) {
await this.redis.del(...keys);
await this.redis.del(`tag:${tag}`);
}
}
}
5. **Cache Warming**
// Pre-populate cache:
async function warmCache() {
// Popular queries
const popularUsers = await db.user.findMany({
orderBy: { views: 'desc' },
take: 100
});
for (const user of popularUsers) {
await redis.setex(`user:${user.id}`, 3600, JSON.stringify(user));
}
}
6. **Query Result Caching**
// Hash complex queries:
function getQueryKey(query: object): string {
return `query:${createHash('md5').update(JSON.stringify(query)).digest('hex')}`;
}
// Cache list queries:
const cacheKey = getQueryKey({ table: 'users', filter: { status: 'active' } });
7. **Monitoring**
// Cache metrics:
// - Hit rate
// - Miss rate
// - Eviction rate
// - Memory usage
// Logging:
const start = Date.now();
const cached = await redis.get(key);
logger.info({
key,
hit: !!cached,
latency: Date.now() - start
});
8. **Distributed Caching**
// Redis Cluster considerations:
// - Key distribution
// - Cross-slot operations
// - Failover handling
Or press ⌘C to copy
Replace these placeholders with your own content before using the prompt.
[{QUERIES][{FREQUENCY][{SIZE][{CONSISTENCY]{
// Try cache first
const cached = await redis.get(`user:${id}{ where: { id }{id}{
await db.user.update({ where: { id }{
async setWithTags(key: string, value: any, tags: string[]) {
await this.redis.set(key, JSON.stringify(value));
for (const tag of tags) {
await this.redis.sadd(`tag:${tag}{
const keys = await this.redis.smembers(`tag:${tag}{
await this.redis.del(...keys);
await this.redis.del(`tag:${tag}{
// Popular queries
const popularUsers = await db.user.findMany({
orderBy: { views: 'desc' }{
await redis.setex(`user:${user.id}{
return `query:${createHash('md5').update(JSON.stringify(query)).digest('hex')}{ table: 'users', filter: { status: 'active' }{
key,
hit: !!cached,
latency: Date.now() - start
}