Caching Adapter
Add intelligent caching to your sync server for 10-100x performance improvement.
Overview
The Caching Adapter sits between your application and database adapter, transparently caching queries and invalidating on writes.
Quick Start
import { SyncServer } from '@gluonic/server'
import { PrismaAdapter } from '@gluonic/server-prisma'
import { CachingAdapter, RedisCache } from '@gluonic/caching-redis'
// 1. Create database adapter
const dbAdapter = PrismaAdapter({ prisma })
// 2. Create cache
const cache = RedisCache({ url: 'redis://localhost:6379' })
// 3. Wrap with caching
const database = CachingAdapter({
adapter: dbAdapter,
cache,
strategies: {
bootstrap: { ttl: 600 }, // Cache 10 minutes
records: { ttl: 60 }, // Cache 1 minute
syncActions: { ttl: 30 } // Cache 30 seconds
}
})
// 4. Use cached adapter
const server = SyncServer({
database, // Caching transparent! ✓
auth
})Cache Implementations
Redis Cache (Production)
import { createRedisCache } from '@gluonic/server/adapters'
const cache = createRedisCache('redis://localhost:6379', {
keyPrefix: 'gluonic:',
maxRetries: 3,
retryDelay: 100
})Memory Cache (Development)
import { createMemoryCache } from '@gluonic/server/adapters'
const cache = createMemoryCache({
maxSize: 1000, // Max entries
ttl: 300 // Default TTL (seconds)
})No-Op Cache (Testing)
import { createNoOpCache } from '@gluonic/server/adapters'
const cache = createNoOpCache() // Pass-through, no cachingCaching Strategies
Bootstrap Caching
strategies: {
bootstrap: {
ttl: 600, // 10 minutes
keyPattern: 'bootstrap:{orgId}',
invalidateOn: ['mutation'] // Clear on any mutation
}
}Record Caching
strategies: {
records: {
ttl: 60, // 1 minute
keyPattern: '{model}:{id}',
invalidateOn: ['update', 'delete']
}
}Query Caching
strategies: {
queries: {
ttl: 30, // 30 seconds
keyPattern: 'query:{model}:{hash}',
invalidateOn: ['mutation']
}
}Invalidation
Automatic Invalidation
// When mutation happens:
await adapter.applyMutations(orgId, userId, [
{ type: 'post', id: '123', op: 'u', patch: { title: 'New' } }
])
// Adapter automatically invalidates:
cache.invalidate('post:123') // Record cache
cache.invalidate('bootstrap:*') // Bootstrap caches
cache.invalidate('query:post:*') // Post queries
// Next request gets fresh data ✓Manual Invalidation
// Clear specific key
await cache.invalidate('post:123')
// Clear pattern
await cache.invalidate('post:*')
// Clear all
await cache.invalidateAll()Performance Impact
Without Caching
GET /sync/v1/bootstrap
→ Query database (1200ms)
→ Serialize (100ms)
→ Total: 1300ms 😔With Caching
GET /sync/v1/bootstrap (first)
→ Query database (1200ms)
→ Serialize (100ms)
→ Cache result
→ Total: 1300ms
GET /sync/v1/bootstrap (cached)
→ Read from Redis (15ms)
→ Total: 15ms ✓
Improvement: 86x faster! 🎉Configuration
Cache Interface
interface CachingAdapter {
get(key: string): Promise<any | null>
set(key: string, value: any, ttl?: number): Promise<void>
invalidate(pattern: string): Promise<void>
wrap<T>(key: string, fn: () => Promise<T>, ttl?: number): Promise<T>
}Wrap Helper
// Automatic caching with wrap()
const data = await cache.wrap(
'bootstrap:org-123',
async () => {
// Only called if cache miss
return await adapter.bootstrap('org-123')
},
600 // TTL: 10 minutes
)Monitoring
Cache Metrics
const metrics = await cache.getMetrics()
console.log({
hits: metrics.hits, // Cache hits
misses: metrics.misses, // Cache misses
hitRate: metrics.hitRate, // Hit rate %
evictions: metrics.evictions // Evicted entries
})Performance Tracking
const cacheAdapter = createCachingAdapter({
adapter: dbAdapter,
cache,
onCacheHit: (key, duration) => {
console.log(`Cache hit: ${key} (${duration}ms saved)`)
},
onCacheMiss: (key) => {
console.log(`Cache miss: ${key}`)
}
})Best Practices
DO ✅
- Cache expensive queries (bootstrap, batch fetch)
- Use short TTLs for frequently changing data
- Use longer TTLs for stable data
- Monitor cache hit rates
- Invalidate on mutations
DON’T ❌
- Cache with infinite TTL
- Cache sensitive data without encryption
- Over-cache (wastes memory)
- Forget to invalidate on writes
Next Steps
- Validation Adapter - Input validation
- Authorization Adapter - Permissions
- Performance - Optimization strategies
Last updated on