- Increase Redis cache TTL from 30 minutes to 24 hours - Add stale-while-revalidate: serve stale cache (>4h) immediately while repopulating in background with SETNX lock to prevent concurrent rebuilds - Add in-memory frontend LRU cache (5 entries) so repeat filter visits are instant without network requests - Invalidate frontend cache on listing refresh and task completion - Add unit tests for get_cache_age, is_cache_stale, acquire_repopulation_lock
45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
/**
|
|
* In-memory LRU cache for streaming listing results.
|
|
*
|
|
* Keyed by a deterministic hash of query parameters so that repeat visits
|
|
* to the same filter combination are instant (no network request).
|
|
*/
|
|
import type { PropertyFeature } from '@/types';
|
|
import type { ParameterValues } from '@/components/FilterPanel';
|
|
|
|
interface CacheEntry {
|
|
features: PropertyFeature[];
|
|
timestamp: number;
|
|
}
|
|
|
|
const cache = new Map<string, CacheEntry>();
|
|
const MAX_ENTRIES = 5;
|
|
|
|
export function makeCacheKey(params: ParameterValues): string {
|
|
const sorted = Object.entries(params)
|
|
.filter(([, v]) => v !== undefined && v !== null && v !== '')
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
.map(([k, v]) => `${k}=${v instanceof Date ? v.toISOString() : v}`);
|
|
return sorted.join('&');
|
|
}
|
|
|
|
export function getCached(params: ParameterValues): PropertyFeature[] | null {
|
|
const key = makeCacheKey(params);
|
|
const entry = cache.get(key);
|
|
if (!entry) return null;
|
|
return entry.features;
|
|
}
|
|
|
|
export function setCached(params: ParameterValues, features: PropertyFeature[]): void {
|
|
const key = makeCacheKey(params);
|
|
if (cache.size >= MAX_ENTRIES && !cache.has(key)) {
|
|
// Evict oldest entry (first inserted)
|
|
const oldest = cache.keys().next().value;
|
|
if (oldest) cache.delete(oldest);
|
|
}
|
|
cache.set(key, { features, timestamp: Date.now() });
|
|
}
|
|
|
|
export function invalidateAll(): void {
|
|
cache.clear();
|
|
}
|