fix(api): use Promise.allSettled for resilient multi-source fetching#826
Conversation
|
@NewCoder3294 is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
koala73
left a comment
There was a problem hiding this comment.
Thanks for the contribution and the well-written PR description!
After tracing through the codebase, most of the changes here are no-ops — the source functions in the affected files already absorb their own errors internally and never reject. Here's the breakdown:
- **** — all 5 source functions (, , etc.) have that returns . They never reject a promise. The new
rejectedbranches +fallbackvariable are dead code. - **** — both
fetchAcledProtestsandfetchGdeltEventswrap intry/catchreturning[]. Also dead code. get-trade-flows.ts/get-trade-barriers.ts—wtoFetchhas its owntry/catchreturningnull. Also dead code.
The one genuinely useful fix is get-fred-series.ts — the two raw fetch() calls there are not individually wrapped, so a timeout on either propagates through Promise.all and discards the whole result. Promise.allSettled here correctly preserves observations even when metadata fails.
My suggestion: open a focused PR with just the get-fred-series.ts change. It's a clean, reviewable, impactful fix that stands on its own. The other 4 files could follow in a separate PR if/when those source functions are refactored to not catch internally — but right now they'd be adding complexity without changing behavior.
Smaller, focused PRs are much easier to review and merge quickly.
Replace Promise.all with Promise.allSettled in five API handlers so that
a single upstream failure no longer discards results from all other
sources. Each conversion falls back to an appropriate default (empty
array, null, or {ok:false}) and logs a console.warn identifying which
source failed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…estructuring Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2c9e8ea to
a2c243f
Compare
…oala73#826) * fix(api): use Promise.allSettled for resilient multi-source fetching Replace Promise.all with Promise.allSettled in five API handlers so that a single upstream failure no longer discards results from all other sources. Each conversion falls back to an appropriate default (empty array, null, or {ok:false}) and logs a console.warn identifying which source failed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cyber): resolve TS18048 possibly-undefined errors in allSettled destructuring Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Several API handlers used
Promise.all()for concurrent data fetching from multiple upstream sources. If any single source failed (network timeout, upstream outage, etc.),Promise.allwould reject immediately and all results from other successful sources would be discarded. This is especially problematic for multi-source aggregation endpoints where partial data is far more useful than no data.This PR converts five
Promise.allcalls toPromise.allSettled, allowing each handler to return partial results when one source is unavailable:unrest/v1/list-unrest-events.ts— ACLED + GDELT protest data. If one source fails, events from the other are still returned. Fallback: empty array per source.economic/v1/get-fred-series.ts— FRED observations + metadata. If metadata fails, observations are still returned with default title/units/frequency. If observations fail, returnsundefined(no usable data).cyber/v1/list-cyber-threats.ts— Five independent threat intel sources (Feodo, URLhaus, C2Intel, OTX, AbuseIPDB). Any subset of sources succeeding yields partial results. Fallback:{ ok: false, threats: [] }per source.trade/v1/get-trade-flows.ts— WTO export + import data. If one direction fails, the other is still returned. Fallback:nullper source.trade/v1/get-trade-barriers.ts— Agricultural + non-agricultural tariff data from WTO. Either dataset can be returned independently. Fallback:nullper source.Intentionally NOT converted
military/v1/list-military-bases.ts— Two halves of an antimeridian bounding box split; both are required for correct spatial results.military/v1/get-theater-posture.ts— Parallel cache writes, not data fetching.supply-chain/v1/get-chokepoint-status.ts— Already uses.catch()handlers for resilience.Behavior on rejection
Each rejected promise now triggers a
console.warnidentifying the failed source and its rejection reason, making upstream outages easy to diagnose in logs.Test plan
tsc --noEmitpasses)console.warnmessages appear in server logs when a source is rejected🤖 Generated with Claude Code