Unified caching layer with Redis and in-memory support
npm install @catalyst-team/cacheThree-layer cache package for Prediction Router V2.
```
┌─────────────────────────────────────────────────────────┐
│ Cache Layers │
├─────────────────────────────────────────────────────────┤
│ │
│ L1: Memory (MemoryAdapter) │
│ ├─ In-process Map with TTL │
│ ├─ Fastest (< 1ms) │
│ ├─ Lost on restart │
│ └─ Not shared across instances │
│ │
│ L2: Redis (RedisAdapter) │
│ ├─ Persistent across restarts │
│ ├─ Shared between instances │
│ ├─ Auto-reconnection support │
│ └─ Fast (1-5ms) │
│ │
│ L3: PostgreSQL (handled by application layer) │
│ └─ Long-term storage for historical data │
│ │
└─────────────────────────────────────────────────────────┘
``
Request → L1 (memory) → hit? → return
→ miss ↓
L2 (Redis) → hit? → return + backfill L1
→ miss ↓
Source API → fetch → update L1 + L2 → return
`bash`
pnpm add @prediction-router/cache
`typescript
import { createCacheManager } from '@prediction-router/cache';
// Create a cache manager with both L1 and L2
const cache = createCacheManager({
l1: { defaultTTL: 60 }, // 60 seconds
l2: { // Redis config
host: 'localhost',
port: 6379,
defaultTTL: 300, // 5 minutes
},
});
// Basic operations
await cache.set('key', { data: 'value' }, { ttl: 60 });
const value = await cache.get<{ data: string }>('key');
await cache.del('key');
// Cache-aside pattern
const data = await cache.getOrSet('expensive-key', async () => {
return await fetchExpensiveData();
}, { ttl: 300 });
`
`typescript
import { MemoryAdapter, CacheManager } from '@prediction-router/cache';
const l1 = new MemoryAdapter({ defaultTTL: 60 });
const cache = new CacheManager({ l1 });
await cache.set('key', 'value');
console.log(await cache.get('key')); // 'value'
`
`typescript
import { RedisClient, RedisAdapter, CacheManager } from '@prediction-router/cache';
const client = new RedisClient({
host: process.env.REDIS_HOST || 'localhost',
port: Number(process.env.REDIS_PORT) || 6379,
});
const l2 = new RedisAdapter(client.getClient(), { defaultTTL: 300 });
const cache = new CacheManager({ l2 });
await cache.set('key', { data: 'complex object' }, { ttl: 600 });
`
`typescript
import { CacheManager, MemoryAdapter, RedisAdapter, RedisClient } from '@prediction-router/cache';
// Create adapters
const l1 = new MemoryAdapter({
defaultTTL: 60,
cleanupIntervalMs: 60000, // Clean up expired entries every minute
});
const redisClient = new RedisClient({
host: 'localhost',
port: 6379,
password: process.env.REDIS_PASSWORD,
db: 0,
keyPrefix: 'app:', // All keys will be prefixed with 'app:'
});
const l2 = new RedisAdapter(redisClient.getClient(), {
defaultTTL: 300,
});
// Create manager
const cache = new CacheManager({ l1, l2 });
// Skip L1 for shared data
await cache.set('shared-data', { value: 123 }, {
ttl: 600,
skipL1: true, // Write directly to Redis, skip memory cache
});
// Get cache statistics
const stats = cache.getStats();
console.log(Hit rate: ${(stats.hitRate * 100).toFixed(2)}%);L1 hits: ${stats.l1Hits}, L2 hits: ${stats.l2Hits}
console.log();
// Health check
const health = await redisClient.healthCheck();
if (health.healthy) {
console.log(Redis latency: ${health.latency}ms);`
}
#### get
Get a value from cache (L1 → L2 fallback).
#### set
Set a value in cache.
Options:
- ttl?: number - Time to live in secondsskipL1?: boolean
- - Skip L1 and write directly to L2
#### del(key: string): Promise
Delete a value from all cache layers.
#### exists(key: string): Promise
Check if a key exists in any cache layer.
#### getOrSet
Get a value from cache, or fetch and cache it if not found.
#### clear(): Promise
Clear all cache layers.
#### getStats(): CacheStats
Get cache statistics (hits, misses, hit rate).
#### healthCheck(): Promise<{ healthy: boolean; latency?: number; error?: string }>
Perform a health check on Redis connection.
#### getInfo(): { connected: boolean; status: string; reconnectAttempts: number }
Get connection information.
#### disconnect(): Promise
Gracefully disconnect from Redis.
`bash`Redis configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your-password
REDIS_DB=0
`bashUnit tests (no Redis required)
pnpm test
MIT