Retries with exponential backoff and jitter
Retry failed AI calls the production way: only retryable errors, exponential backoff with equal jitter, the server's retry delay when it gives one, and a testable wait.
A retry is simple: try again. Doing it well takes three decisions. Whether to retry, which classifying errors settled. How long to wait. And when to stop.
How long to wait
- Not immediately. An overloaded service that fails now will fail again a millisecond later.
- Longer each time: . The ceiling doubles: 1s, 2s, 4s, capped at a maximum.
- Randomly: . Pick a wait between half the ceiling and the full ceiling.
- retry 10.5–1s
- retry 21–2s
- retry 32–4s
If the server sends a retry delay, that wins: wait it plus up to 20%.
attempt 0 → ceiling 1000 → wait 750ms
attempt 1 → ceiling 2000 → wait 1500ms
attempt 2 → ceiling 4000 → wait 3000ms
server said "12s" → wait 12000 + up to 20%withRetry(fn, options)
Call fn. If it throws, classify the error. Rethrow it if it isn't retryable or you've used every retry. Otherwise work out the delay, report it with onRetry (the UI will show "retrying in 2s"), wait, and loop.
Under the hood — Why is `wait` an option?
Real code waits with setTimeout. A test of three retries would then take seven real seconds. Passing a fake wait that records the delay and returns immediately lets the test check the exact delays in a millisecond. The same goes for random: fixing it at 0.5 makes the delays predictable. Your exercise uses both.
Key takeaways
- Only retry errors that can succeed later, and give up after a few tries.
- Double the wait each time and add randomness, so clients don't all retry at once.
- When the server says how long to wait, wait that long.
Sign in to run the exercise
Reading is free. Writing code here needs an account so we have somewhere to keep your Gemini key and the +35 XP you are about to earn.