fix(safeFetch): exponential backoff, HTTP 429 awareness, Retry-After support#121
Open
kawacukennedy wants to merge 1 commit into
Open
fix(safeFetch): exponential backoff, HTTP 429 awareness, Retry-After support#121kawacukennedy wants to merge 1 commit into
kawacukennedy wants to merge 1 commit into
Conversation
…support safeFetch() had five issues affecting all 27+ source modules: 1. No HTTP 429 awareness — rate-limited responses treated as generic errors 2. Fixed backoff — 2000*(i+1)ms regardless of error type 3. All errors retried equally — 400/404 retried same as 503 4. AbortController timer leak — clearTimeout only on success path 5. No POST/body support — BLS, ReliefWeb had to implement their own fetch Rewrite with: - Status-code classification (only retry 408/429/500/502/503/504) - Exponential backoff with jitter (100ms*2^i + random(0,1000), capped 30s) - Retry-After header parsing (capped at 60s) - Timer cleanup in catch path - POST/body method support Update OpenSky getFlightsInArea to use retries: 2 for 429 resilience. Add 18 unit tests covering all new behaviors. Fixes the known limitation documented in README.md:498.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
safeFetch()inapis/utils/fetch.mjshas five issues affecting all 27+ source modules:2000 × (i+1)ms regardless of error type. If a server sendsRetry-After: 30, the header is ignored.clearTimeout(timer)is only called on the success path. (Noted in issue fix: safeFetch timer leak, env quote stripping, source count #84.)Root Cause
safeFetchatapis/utils/fetch.mjs:3-28was a single flat retry loop with no status-code classification, no exponential backoff, no Retry-After parsing, and timer cleanup only on success.Solution
apis/utils/fetch.mjs— Rewrite safeFetchmin(100ms × 2^i, 30s) + random(0, 1000ms). Total cumulative backoff capped at 30s.Retry-After: N, wait exactly N seconds (capped at 60s to prevent pathological waits).clearTimeout(timer)in both success and catch paths.methodandbodyoptions.retries: 1,method: 'GET') unchanged.apis/sources/opensky.mjs— Explicit retriesOpenSky is the most rate-limited source (4k credits/day unauthenticated, 10 parallel hotspot queries). Setting
retries: 2ongetFlightsInAreagives exponential backoff two chances to succeed before a hotspot returns empty data.test/safe-fetch.test.mjs— 18 new unit testsCovers: success, non-JSON, 400/403/404 bail, 429/503/408 retry, Retry-After, network error, timeout abort, POST body, custom headers, max backoff cap.
Testing
node --test test/safe-fetch.test.mjs— 18/18 passnode --test(all tests) — 63/63 pass, 0 fail, 1 skipped (needs API key)node diag.mjs— All 12 imports OK, port available, server loadsnode -e \"import('./apis/utils/fetch.mjs')\"— Module loads without errorSuggested labels
bug,performance,enhancement