cache
This commit is contained in:
28
lib/feeds.ts
28
lib/feeds.ts
@@ -5,24 +5,36 @@ import { computeGroupTables, computeThirdPlaceTable } from "./standings";
|
||||
import { FIFA_GROUP_MAP, FIFA_STAGE_MAP } from "./fifa-constants";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Caching: einfacher In-Memory-Cache mit TTL.
|
||||
// Caching: In-Memory-Cache mit TTL + stale-while-revalidate.
|
||||
// Bei abgelaufenem Cache wird der alte Wert sofort zurückgegeben und die
|
||||
// Erneuerung im Hintergrund angestoßen (keine Wartezeit für den Nutzer).
|
||||
// ----------------------------------------------------------------------------
|
||||
interface CacheEntry<T> { value: T; expires: number; }
|
||||
interface CacheEntry<T> { value: T; expires: number; refreshing?: boolean; }
|
||||
const cache = new Map<string, CacheEntry<unknown>>();
|
||||
|
||||
export async function cached<T>(key: string, ttlMs: number, fn: () => Promise<T>): Promise<T> {
|
||||
const hit = cache.get(key) as CacheEntry<T> | undefined;
|
||||
const now = Date.now();
|
||||
|
||||
// Frischer Cache → direkt zurück
|
||||
if (hit && hit.expires > now) return hit.value;
|
||||
try {
|
||||
|
||||
// Abgelaufen, aber vorhanden → sofort alten Wert liefern, im Hintergrund erneuern
|
||||
if (hit) {
|
||||
if (!hit.refreshing) {
|
||||
hit.refreshing = true;
|
||||
fn()
|
||||
.then((value) => { cache.set(key, { value, expires: Date.now() + ttlMs }); })
|
||||
.catch((err) => { console.error(`[cache] Hintergrund-Refresh fehlgeschlagen (${key}):`, err); })
|
||||
.finally(() => { const e = cache.get(key) as CacheEntry<T> | undefined; if (e) e.refreshing = false; });
|
||||
}
|
||||
return hit.value;
|
||||
}
|
||||
|
||||
// Kaltstart: kein Cache → synchron laden
|
||||
const value = await fn();
|
||||
cache.set(key, { value, expires: now + ttlMs });
|
||||
return value;
|
||||
} catch (err) {
|
||||
// Bei Upstream-Fehler abgelaufenen Cache weiterverwenden, statt hart zu failen.
|
||||
if (hit) return hit.value;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user