mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-05-13 18:46:21 +02:00
* perf(baseline): move temporal baseline for news+fires to server-side Every browser client was calling record-baseline-snapshot (POST) + get-temporal-baseline (GET) on every data refresh from 5 call sites. With N concurrent users this created N identical writes and ~5N reads per cycle — causing 429 rate limiting and statistically biased baselines. Phase 1 moves news and satellite_fires to server-side computation: - New ListTemporalAnomalies RPC reads counts from existing Redis keys (news:insights:v1, wildfire:fires:v1), computes anomalies against v2 baselines, applies Welford update (1 sample/cycle), caches 15min - Bootstrap hydration delivers anomalies on page load (zero extra calls) - Client refreshes via RPC every 10min (1 cached call vs 5N before) - Remaining 3 types (military_flights, vessels, ais_gaps) stay client-side - Owner-guarded distributed lock prevents concurrent computation - All reads/writes use prefix-aware getCachedJson/setCachedJson Expected ~60% reduction in baseline-related Vercel invocations. * fix(temporal): per-invocation lock owner and immediate refresh on cold cache P1: When bootstrap has no temporal anomaly data (cold cache, expired snapshot, fresh deploy), fire refreshTemporalBaseline() immediately instead of waiting up to 10 minutes for the scheduled refresh. P2: Generate lockOwner per invocation via makeLockOwner() instead of once at module load. Prevents warm edge isolates from cross-releasing each other's locks when one invocation outlives the 30s TTL. * fix(temporal): use TTL-only lock instead of TOCTOU GET-then-DEL release The non-atomic GET→check-owner→DEL release was vulnerable to a race where the TTL expires between GET and DEL, allowing a new lock holder to be evicted. Simplify by relying solely on the 30s TTL for lock expiry — the computation completes well within that window.
58 lines
2.6 KiB
TypeScript
58 lines
2.6 KiB
TypeScript
/**
|
|
* Static cache keys for the bootstrap endpoint.
|
|
* Only keys with NO request-varying suffixes are included.
|
|
*/
|
|
export const BOOTSTRAP_CACHE_KEYS: Record<string, string> = {
|
|
earthquakes: 'seismology:earthquakes:v1',
|
|
outages: 'infra:outages:v1',
|
|
serviceStatuses: 'infra:service-statuses:v1',
|
|
sectors: 'market:sectors:v1',
|
|
etfFlows: 'market:etf-flows:v1',
|
|
macroSignals: 'economic:macro-signals:v1',
|
|
bisPolicy: 'economic:bis:policy:v1',
|
|
bisExchange: 'economic:bis:eer:v1',
|
|
bisCredit: 'economic:bis:credit:v1',
|
|
shippingRates: 'supply_chain:shipping:v2',
|
|
chokepoints: 'supply_chain:chokepoints:v2',
|
|
minerals: 'supply_chain:minerals:v2',
|
|
giving: 'giving:summary:v1',
|
|
climateAnomalies: 'climate:anomalies:v1',
|
|
wildfires: 'wildfire:fires:v1',
|
|
marketQuotes: 'market:stocks-bootstrap:v1',
|
|
commodityQuotes: 'market:commodities-bootstrap:v1',
|
|
cyberThreats: 'cyber:threats-bootstrap:v2',
|
|
techReadiness: 'economic:worldbank-techreadiness:v1',
|
|
progressData: 'economic:worldbank-progress:v1',
|
|
renewableEnergy: 'economic:worldbank-renewable:v1',
|
|
positiveGeoEvents: 'positive-events:geo-bootstrap:v1',
|
|
theaterPosture: 'theater-posture:sebuf:stale:v1',
|
|
riskScores: 'risk:scores:sebuf:stale:v1',
|
|
naturalEvents: 'natural:events:v1',
|
|
flightDelays: 'aviation:delays-bootstrap:v1',
|
|
insights: 'news:insights:v1',
|
|
predictions: 'prediction:markets-bootstrap:v1',
|
|
cryptoQuotes: 'market:crypto:v1',
|
|
gulfQuotes: 'market:gulf-quotes:v1',
|
|
stablecoinMarkets: 'market:stablecoins:v1',
|
|
unrestEvents: 'unrest:events:v1',
|
|
iranEvents: 'conflict:iran-events:v1',
|
|
ucdpEvents: 'conflict:ucdp-events:v1',
|
|
temporalAnomalies: 'temporal:anomalies:v1',
|
|
};
|
|
|
|
export const BOOTSTRAP_TIERS: Record<string, 'slow' | 'fast'> = {
|
|
bisPolicy: 'slow', bisExchange: 'slow', bisCredit: 'slow',
|
|
minerals: 'slow', giving: 'slow', sectors: 'slow',
|
|
progressData: 'slow', renewableEnergy: 'slow',
|
|
etfFlows: 'slow', shippingRates: 'slow', wildfires: 'slow',
|
|
climateAnomalies: 'slow', cyberThreats: 'slow', techReadiness: 'slow',
|
|
theaterPosture: 'slow', naturalEvents: 'slow',
|
|
cryptoQuotes: 'slow', gulfQuotes: 'slow', stablecoinMarkets: 'slow',
|
|
unrestEvents: 'slow', ucdpEvents: 'slow',
|
|
earthquakes: 'fast', outages: 'fast', serviceStatuses: 'fast',
|
|
macroSignals: 'fast', chokepoints: 'fast', riskScores: 'fast',
|
|
marketQuotes: 'fast', commodityQuotes: 'fast', positiveGeoEvents: 'fast',
|
|
flightDelays: 'fast', insights: 'fast', predictions: 'fast',
|
|
iranEvents: 'fast', temporalAnomalies: 'fast',
|
|
};
|