(
...args: Parameters<T>
)
| 236 | |
| 237 | // L1 LRU (60s) + L2 Redis. clear() deletes Redis + local LRU; other nodes may serve stale from LRU for up to 60s. |
| 238 | const cachedFn = async ( |
| 239 | ...args: Parameters<T> |
| 240 | ): Promise<Awaited<ReturnType<T>>> => { |
| 241 | const key = getKey(...args); |
| 242 | |
| 243 | // L1: in-memory LRU first (offloads Redis on hot keys) |
| 244 | const lruHit = lruCache.get(key); |
| 245 | if (lruHit !== undefined && shouldCache(lruHit, options)) { |
| 246 | return lruHit as Awaited<ReturnType<T>>; |
| 247 | } |
| 248 | |
| 249 | // L2: Redis (shared across instances) |
| 250 | const cached = await getRedisCache().get(key); |
| 251 | if (cached) { |
| 252 | const parsed = parseCache(cached); |
| 253 | if (shouldCache(parsed, options)) { |
| 254 | lruCache.set(key, parsed); |
| 255 | return parsed; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | // Cache miss: execute function |
| 260 | const result = await fn(...(args as any)); |
| 261 | |
| 262 | if (shouldCache(result, options)) { |
| 263 | lruCache.set(key, result); |
| 264 | getRedisCache() |
| 265 | .setex(key, expireInSec, JSON.stringify(result)) |
| 266 | .catch(() => { |
| 267 | // ignore error |
| 268 | }); |
| 269 | } |
| 270 | |
| 271 | return result; |
| 272 | }; |
| 273 | |
| 274 | cachedFn.getKey = getKey; |
| 275 | cachedFn.clear = (...args: Parameters<T>) => { |
no test coverage detected