core practice · coding problem
Exponential backoff with full jitter
Implement backoffDelays(attempts, baseMs, capMs, rand) returning the delay for each attempt using capped exponential backoff with FULL jitter: delay = rand() * min(capMs, baseMs * 2^attempt), floored to an integer. `rand` is a supplied function returning [0,1) so the result is deterministic under test. Attempt numbering starts at 0.
The mechanism
A naive retry is a load multiplier aimed at a service that is already struggling, and synchronised clients retrying on the same schedule produce a thundering herd. Exponential backoff spreads them in time and jitter breaks the synchronisation; a retry budget caps the amplification. A circuit breaker is the admission that retrying is now pointless: after enough failures it fails fast, gives the dependency room to recover, then lets a trial request through. Retries are only safe at all if the operation is idempotent.
Expected evidence
backoffDelays(4, 100, 1000, () => 1) -> [100, 200, 400, 800]
Try this drill in the practice workspace →
Hints when you need them
- Cap the exponential FIRST, then apply jitter to the capped value — the other order defeats the cap.
- Full jitter means the delay is uniform in [0, ceiling), not ceiling ± a wobble.
Watch for these mistakes
- Retrying non-idempotent writes, so a timeout becomes a double charge
- Backoff without jitter, which keeps every client synchronised and reproduces the herd
- Retrying at several layers at once — three layers of three retries is twenty-seven requests
- Retrying a 4xx: the request is wrong, and repeating it will not make it right