Retry with full jitter
When an API goes down, every client fails at once and, with fixed backoff, retries at the same instant — a thundering herd that keeps the service down. AWS's 'full jitter' fix is to pick a random wait between zero and the backoff ceiling.
Implement retryWithJitter(task, options) where options may contain attempts (default 3), baseDelay (default 100) and random (default Math.random). Call task(attemptIndex) with the zero-based attempt number. Resolve with its value as soon as an attempt succeeds. After a failed attempt at index i, if further attempts remain, call random() exactly once and wait Math.floor(random() * baseDelay * 2 ** i) milliseconds before the next attempt. After the final attempt fails, reject with that last error and do not call random again.
Arguments
task(attemptIndex: number) => Promise<T>- The work to run, called with the zero-based attempt number.
options{ attempts?: number, baseDelay?: number, random?: () => number }attemptsdefaults to3,baseDelayto100ms,randomtoMath.random.
Returns
Promise<T> — Resolves with the first successful attempt's value. Rejects with the final attempt's error after all retries are exhausted.
Examples
let calls = 0;
const value = await retryWithJitter(async () => {
calls++;
if (calls < 3) throw new Error("flaky");
return "recovered";
}, { attempts: 5, baseDelay: 10, random: () => 0 });
// value === "recovered", calls === 3Keeps trying until an attempt succeeds.
// With random: () => 1, waits scale: 20ms after attempt 0, 40ms after attempt 1.
try {
await retryWithJitter(async () => { throw new Error("down"); }, {
attempts: 3, baseDelay: 20, random: () => 1,
});
} catch (error) {
// error.message === "down" — final attempt's error
}Ceiling doubles each round; actual wait is a random slice of it.
What it has to do
- Call
taskwith the zero-based attempt index. - Resolve as soon as an attempt succeeds, without waiting again.
- Call
randomexactly once per wait, and never after the final attempt. - Wait
Math.floor(random() * baseDelay * 2 ** attemptIndex)milliseconds between attempts. - Reject with the error from the final attempt.
Notes
- The actual wait is
Math.floor(random() * baseDelay * 2 ** attemptIndex)— the ceiling doubles each time, the real wait is a random slice of it. - Call
randomexactly once per wait, and don't call it after the last attempt — tests enforce both to catch off-by-one bugs.
Stuck? The javascript course covers everything this challenge needs.
- 1.returns the first success without waiting
- 2.retries until an attempt succeeds
- 3.passes the attempt index to the task
- 4.calls random once per wait and not after the last attempt
- 5.scales the wait with the attempt index
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.