commit · HEAD^@e071dae → HEAD@1c38faf · claude-opus-5 (cursor)
A fixed 200ms delay sends every retrying client back at the same instant, so a service that is shedding load gets a synchronized second wave and sheds that too. Retries now double their window per attempt and pick a random wait inside it, capped so a single call cannot stall a request indefinitely.
This file really exists in the repo, so this review is live: the controls in the gutter discard an added line or put a removed one back, clicking a highlighted piece of a changed line takes just that piece back to the old text, and edit writes your own version straight to examples/retry.ts. Three parts of the change are deliberately worth rejecting — a leftover debug log, a widened list of retryable statuses, and a base delay nudged from 200ms to 250ms on the same line as a rename worth keeping. git checkout examples/ undoes anything you apply.
npm test -- example-retrynpm run typecheckAn unbounded doubling window reaches 25 seconds by the sixth attempt, which outlives most request deadlines and turns a retry into a hang. The cap is an option rather than a constant because a background job can afford a longer wait than a request handler.
$ npm test -- example-retryThe comment was dropped because the function no longer only answers "is this safe to send again" — but that sentence was the only place the rule was written down, and removing it loses the rule.
502 and 504 were added because both are usually a proxy failing in front of a healthy service, so the call is worth repeating. But a proxy that already forwarded the request returns the same 502, which makes a retry unsafe for any caller that is not idempotent. This is the line to discard if yours is not.
Full jitter, rather than exponential-with-half-jitter, because the point is to de-correlate clients that all failed at the same moment. Picking uniformly from the whole window spreads the second wave widest for the same mean wait.
$ npm test -- example-retryTwo things happened on this line. The local was renamed because delayMs read as "the delay" when it is only the first window, and the default moved from 200ms to 250ms. The rename is worth keeping; the new number is not something this change had any reason to touch.
250 to take that part back to 200 and keep the rename5 seconds is a guess at "long enough to outlast a restart, short enough that a caller has not given up".
This log was added while checking that the windows grew as intended, and it should not have survived. It prints on every retry of every call, has no logger behind it, and leaks timing into stdout.