Add multi-layer caching: 24h Redis TTL, stale-while-revalidate, frontend LRU cache
- 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
This commit is contained in:
parent
04bda8c127
commit
1ae00b7cbf
5 changed files with 270 additions and 1 deletions
45
frontend/src/services/listingCache.ts
Normal file
45
frontend/src/services/listingCache.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue