mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-05-13 10:36: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.