Skip to content

feat(cache): negative-result caching for cachedFetchJson#466

Merged
koala73 merged 1 commit into
mainfrom
feat/negative-result-caching
Feb 27, 2026
Merged

feat(cache): negative-result caching for cachedFetchJson#466
koala73 merged 1 commit into
mainfrom
feat/negative-result-caching

Conversation

@koala73

@koala73 koala73 commented Feb 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • When upstream APIs return errors (HTTP 403/429/timeout), fetchers return null. Previously null was not cached, causing repeated request storms every refresh cycle against broken APIs
  • Adds a sentinel value (__WM_NEG__) cached with a short 2-minute TTL on null results — subsequent requests within that window skip upstream entirely
  • Thrown errors (transient like ETIMEDOUT) bypass sentinel caching and retry immediately
  • Filters sentinels from getCachedJsonBatch pipeline reads to prevent leakage
  • Fixes pre-existing theater posture coalescing test (expected 2 OpenSky fetches for 2 theater query regions, not 1)

Trigger: WTO API returning HTTP 403 for all 6 concurrent /data requests, every 10-minute cycle, indefinitely. But the fix protects all 52 handlers using cachedFetchJson.

Design decisions

  • Sentinel string vs separate :neg key: Zero extra Redis calls on cache hit (no second GET), natural key expiration
  • T extends object constraint: Compile-time safety against sentinel collision — all 52 callers use arrays/objects
  • Default 2-min negative TTL: Long enough to prevent storms, short enough for recovery. Per-caller override via optional 4th parameter

Test plan

  • npx tsc --noEmit — frontend types pass
  • npx tsc --noEmit -p tsconfig.api.json — no new API type errors
  • Pre-push hook: typecheck + full Vite build pass
  • 15/15 redis caching tests pass (3 new negative-cache tests + fixed theater posture test)
  • New test: sentinel suppresses subsequent upstream calls
  • New test: cachedFetchJsonWithMeta returns { data: null, source: 'cache' } on sentinel hit
  • New test: thrown fetcher errors skip sentinel caching

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).
@vercel

vercel Bot commented Feb 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Building Building Preview, Comment Feb 27, 2026 2:51pm
worldmonitor-finance Building Building Preview, Comment Feb 27, 2026 2:51pm
worldmonitor-happy Building Building Preview, Comment Feb 27, 2026 2:51pm
worldmonitor-startup Building Building Preview, Comment Feb 27, 2026 2:51pm

Request Review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@koala73
koala73 merged commit 7f58a4e into main Feb 27, 2026
5 of 6 checks passed
@koala73
koala73 deleted the feat/negative-result-caching branch February 27, 2026 20:50
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).
koala73 added a commit that referenced this pull request Mar 1, 2026