82 lines
1.8 KiB
TypeScript
82 lines
1.8 KiB
TypeScript
import { LRUCache } from 'lru-cache';
|
|
import { logger } from '../utils/logger';
|
|
|
|
/**
|
|
* Fallback cache for graceful degradation
|
|
*
|
|
* Stores successful responses with extended TTL (1 hour) to serve
|
|
* when the primary data source (Flashpoint database) is unavailable
|
|
*/
|
|
export class FallbackCache<T = any> {
|
|
private cache: LRUCache<string, { data: T; cachedAt: number }>;
|
|
private readonly FALLBACK_TTL = 60 * 60 * 1000; // 1 hour
|
|
|
|
constructor(maxSize: number = 500) {
|
|
this.cache = new LRUCache<string, { data: T; cachedAt: number }>({
|
|
max: maxSize,
|
|
ttl: this.FALLBACK_TTL,
|
|
updateAgeOnGet: true,
|
|
allowStale: true, // Allow stale data in fallback mode
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Store data in fallback cache
|
|
*/
|
|
set(key: string, data: T): void {
|
|
this.cache.set(key, {
|
|
data,
|
|
cachedAt: Date.now(),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get data from fallback cache
|
|
* Returns both data and metadata about cache age
|
|
*/
|
|
get(key: string): { data: T; cachedAt: number; age: number } | null {
|
|
const cached = this.cache.get(key);
|
|
if (!cached) {
|
|
return null;
|
|
}
|
|
|
|
const age = Date.now() - cached.cachedAt;
|
|
|
|
logger.debug('[FallbackCache] Serving cached data', {
|
|
key: key.substring(0, 50),
|
|
age: `${Math.round(age / 1000)}s`,
|
|
cachedAt: new Date(cached.cachedAt).toISOString(),
|
|
});
|
|
|
|
return {
|
|
data: cached.data,
|
|
cachedAt: cached.cachedAt,
|
|
age,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if key exists in cache
|
|
*/
|
|
has(key: string): boolean {
|
|
return this.cache.has(key);
|
|
}
|
|
|
|
/**
|
|
* Clear cache
|
|
*/
|
|
clear(): void {
|
|
this.cache.clear();
|
|
}
|
|
|
|
/**
|
|
* Get cache statistics
|
|
*/
|
|
getStats(): { size: number; max: number } {
|
|
return {
|
|
size: this.cache.size,
|
|
max: this.cache.max,
|
|
};
|
|
}
|
|
}
|