SIGN IN SIGN UP
koala73 / worldmonitor UNCLAIMED

Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface

0 0 157 TypeScript

fix(api/latest-brief): retry Upstash read once on transient timeout (#3924)

* fix(api/latest-brief): retry Upstash read once on transient timeout

WORLDMONITOR-QJ surfaced as DOMException("operation aborted due to
timeout") at api/latest-brief.ts on Upstash GET. Frequency: 4 events /
19 days, including a 2026-05-13 same-minute double-fire across us-west
and eu-central — a real Upstash regional incident rather than per-user
noise. The handler caught the timeout and returned 503; users saw
"service unavailable" panel on the dashboard.

Add a one-retry helper around `readLatestPointer` + `readBriefPreview`
that re-runs the Upstash GET when AbortSignal.timeout fires. First
attempt gets a 6s budget (up from the shared 3s default); retry shortens
to 3s so total worst-case wall time stays under Vercel Edge's ~25s
initial-response cap after the validateBearerToken + getEntitlements
preflight. Sustained outages still time out cleanly and hit the existing
503 fallback path.

Recovery telemetry: every retry attempt fires `captureSilentError`
tagged `step: 'upstash-retry-attempt'` so the rate of
blipped-but-recovered cases stays visible in Sentry — without it,
successful retries would only appear in Vercel logs and we'd lose the
signal that informs whether the budget is sized right.

Tests: append regression suite asserting (1) one retry on
`name === 'TimeoutError'`, (2) no retry on other error shapes, (3)
re-throw when both attempts time out, (4) per-attempt budgets fire in
the documented order (6s → 3s). The helper and constants are exported as
a test seam (matches `executeTool` in api/mcp/dispatch.ts).

Notes:
- Shared `_upstash-json.js` timeout default stays at 3s; longer budget
  is opt-in via explicit `timeoutMs` argument so the 13 other Upstash
  callers (MCP fan-out, brief share-url, symbol-search, etc.) keep
  their fast-fail semantics.
- Duck-types on `err.name === 'TimeoutError'` rather than
  `instanceof DOMException` so retry survives cross-realm cases in test
  runners where undici's DOMException can differ from globalThis.
- Hoists `session.userId` to a local const so the retry-helper arrow
  closures capture `string` rather than `string | undefined` (TS
  narrowing doesn't survive into closure capture sites).

* fix(api): retry latest brief reads on abort
E
Elie Habib committed
526f916e36dbbbf555c416dda83d7eabcd460d83
Parent: c613a7f
Committed by GitHub <noreply@github.com> on 5/27/2026, 3:19:21 PM