FrontendPro

88Implement retry with exponential backoff and jitter

mediumAbout 40 minutesCodingresiliencenetworkalgorithms

Problem

Implement two functions:

computeDelay(attempt, { baseDelay = 100, factor = 2, maxDelay = 10000, jitter = "full", random = Math.random }) returns the wait in ms before retry number attempt (0 for the first retry):

  • the exponential part is min(maxDelay, baseDelay * factor ** attempt);
  • jitter: "none" returns it unchanged; "full" returns random() * exp; "equal" returns exp / 2 + random() * exp / 2.

retryWithBackoff(fn, options) calls the async fn(attempt) and retries failures:

  • options: retries = 3 (retries after the first try), the computeDelay options, shouldRetry, onRetry(error, attempt, delay), signal, and sleep = (ms) => new Promise(…) (injectable for tests);
  • by default, retry network errors (TypeError) and errors with status 408, 429 or 5xx; never retry other 4xx;
  • if an error has retryAfter (milliseconds, for example parsed from a Retry-After header), wait at least that long;
  • stop and reject with signal.reason when signal is aborted;
  • reject with the last error when retries run out.
const data = await retryWithBackoff(() => api.get("/report"), { retries: 5, baseDelay: 200, maxDelay: 5000 });

Try it yourself

Write your solution, run it, then submit to check it against the tests.

App.jsxReact + DOM

Step-by-step

Doubling the wait after each failure (100, 200, 400, 800 ms…) gives a struggling server time to recover. Cap it with maxDelay, or the fifteenth retry would wait an hour.

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 5 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever