( key: string, expireInSec: number, fn: () => Promise<T>, useLruCache?: boolean )
| 14 | }); |
| 15 | |
| 16 | export async function getCache<T>( |
| 17 | key: string, |
| 18 | expireInSec: number, |
| 19 | fn: () => Promise<T>, |
| 20 | useLruCache?: boolean |
| 21 | ): Promise<T> { |
| 22 | // L1 Cache: Check global LRU cache first (in-memory, instant) |
| 23 | if (useLruCache) { |
| 24 | const lruHit = globalLruCache.get(key); |
| 25 | if (lruHit !== undefined) { |
| 26 | return lruHit as T; |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | // L2 Cache: Check Redis cache (shared across instances) |
| 31 | const hit = await getRedisCache().get(key); |
| 32 | if (hit) { |
| 33 | const parsed = parseCache(hit); |
| 34 | |
| 35 | // Store in LRU cache for next time |
| 36 | if (useLruCache) { |
| 37 | globalLruCache.set(key, parsed, { |
| 38 | ttl: expireInSec * 1000, // Use the same TTL as Redis |
| 39 | }); |
| 40 | } |
| 41 | |
| 42 | return parsed; |
| 43 | } |
| 44 | |
| 45 | // Cache miss: Execute function |
| 46 | const data = await fn(); |
| 47 | |
| 48 | // Store in both caches |
| 49 | if (useLruCache) { |
| 50 | globalLruCache.set(key, data, { |
| 51 | ttl: expireInSec * 1000, |
| 52 | }); |
| 53 | } |
| 54 | // Fire and forget Redis write for better performance |
| 55 | getRedisCache().setex(key, expireInSec, JSON.stringify(data)); |
| 56 | |
| 57 | return data; |
| 58 | } |
| 59 | |
| 60 | // Helper functions for managing global LRU cache |
| 61 | export function clearGlobalLruCache(key?: string) { |
no test coverage detected