feat(cache): negative-result caching for cachedFetchJson#466
Merged
Conversation
When upstream APIs return errors (HTTP 403, 429, timeout), fetchers
return null. Previously null results were not cached, causing repeated
request storms against broken APIs every refresh cycle.
Now caches a sentinel value ('__WM_NEG__') with a short 2-minute TTL
on null results. Subsequent requests within that window get null
immediately without hitting upstream. Thrown errors (transient) skip
sentinel caching and retry immediately.
Also filters sentinels from getCachedJsonBatch pipeline reads and fixes
theater posture coalescing test (expected 2 OpenSky fetches for 2
theater query regions, not 1).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
5 tasks
koala73
added a commit
that referenced
this pull request
Mar 1, 2026
When upstream APIs return errors (HTTP 403, 429, timeout), fetchers
return null. Previously null results were not cached, causing repeated
request storms against broken APIs every refresh cycle.
Now caches a sentinel value ('__WM_NEG__') with a short 2-minute TTL
on null results. Subsequent requests within that window get null
immediately without hitting upstream. Thrown errors (transient) skip
sentinel caching and retry immediately.
Also filters sentinels from getCachedJsonBatch pipeline reads and fixes
theater posture coalescing test (expected 2 OpenSky fetches for 2
theater query regions, not 1).
Summary
null. Previouslynullwas not cached, causing repeated request storms every refresh cycle against broken APIs__WM_NEG__) cached with a short 2-minute TTL onnullresults — subsequent requests within that window skip upstream entirelygetCachedJsonBatchpipeline reads to prevent leakageTrigger: WTO API returning HTTP 403 for all 6 concurrent
/datarequests, every 10-minute cycle, indefinitely. But the fix protects all 52 handlers usingcachedFetchJson.Design decisions
:negkey: Zero extra Redis calls on cache hit (no second GET), natural key expirationT extends objectconstraint: Compile-time safety against sentinel collision — all 52 callers use arrays/objectsTest plan
npx tsc --noEmit— frontend types passnpx tsc --noEmit -p tsconfig.api.json— no new API type errorscachedFetchJsonWithMetareturns{ data: null, source: 'cache' }on sentinel hit