Repository navigation
feat(client): retry uncharged failures by default, with full-jitter backoff and a time budget - #58
Draft
gonzalo-zenrows wants to merge 1 commit into
Draft
gonzalo-zenrows wants to merge 1 commit into
gonzalo-zenrows wants to merge 1 commit into
Conversation
… and a time budget A 429, 502, 503 or 504 from the API is never charged and means "try again", so the client now retries those (and network errors before any response) by default, waiting the server's Retry-After or a full-jitter backoff instead of a fixed doubling delay. A 422 is no longer retried: the API no longer sends a retryable 422. A timeout or abort is never retried, because the server may still finish and charge the request. - retries defaults to 2 (was 0); retries: 0 turns retries off - new retryMaxWait (seconds, default 30) caps one backoff wait - new retryBudget (seconds, default 90): no retry starts past it - Retry-After in whole seconds is honoured, capped at 30 s
Author
|
Same retry policy across all clients (429/502/503/504 and pre-response connection errors; 2 retries by default; full jitter; Retry-After capped at 30 s; 90 s total budget; timeouts never retried):
|
This was referenced Oct 16, 2026
Draft
This branch has not been deployed
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.
What changed
fetch(),extract()andpost()now share one retry policy, the same one the Python SDK, Go SDK and CLI are adopting in parallel PRs:no_data_extractedwas already final; now every 422 is.Retry-Afterin whole seconds, capped at 30 s. Otherwise full jitter:uniform(0.25 s, min(retryMaxWait, 1 s * 2^attempt)), whereattemptis the 0-based retry index (first retry 0.25–1 s, second 0.25–2 s). An HTTP-dateRetry-Afterfalls back to jitter.retryBudget. The last response or error is returned as-is.extract()fallback toautoparseonREQS007/AUTH010is unchanged: still one extra request (which gets its own retries, as before).It stays on
fetch-retry, with no second retry layer: the policy lives insrc/retry.tsand is passed per request asretryOn/retryDelay, so each request has its own clock and budget. A retried response's body is cancelled so its connection is freed.New defaults
retries02retryMaxWait(seconds)30retryBudget(seconds)90The
retriesdefault is a public behaviour change, so this is afeat(minor release with a changelog entry via release-please). Callers who already setretriesget the new wait curve and status set.How to opt out
Tests
pnpm checkis clean.pnpm test -- --run: 403 passed, 6 skipped (e2e). Retry tests use fake timers and an injectable clock and random source, so they run in milliseconds:tests/retries.test.ts: retried and non-retried statuses, network error vs abort/timeout, jitter bounds per attempt,retryMaxWaitcap,Retry-Afterhonoured and capped at 30 s, non-numericRetry-Afterfalls back to jitter, budget respected (unit and end to end), no retry on 400/422, autoparse fallback unchanged.tests/retry-count.test.ts: default makes 3 calls on a 503;retries: 0makes 1.tests/no-data-extracted.test.ts: a non-no_data_extracted422 is now not retried.tests/index.test.ts: two exact-argument assertions on the wrapped fetch now useobjectContaining, since each call also carriesretryOn/retryDelay.README updated to describe the policy and the new options.
Not covered