CodePark/ questions / Retries, timeouts & resilience
START PRACTICINGPRACTICE
Backend question · System design & architecture › Retries, timeouts & resilience

Explain what this retry helper does. Why exponential backoff, why jitter, and when should you not retry at all?

async function withRetry(fn, { retries = 4, base = 100, cap = 5000 } = {}) {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt >= retries || !isTransient(err)) throw err;
      const max = Math.min(cap, base * 2 ** attempt);
      await sleep(Math.random() * max); // full jitter
    }
  }
}

The helper retries a failing call up to four more times, but only for transient errors. A transient error is a temporary one that may succeed on the next try. The wait limit doubles on each attempt (100, 200, 400, 800 ms) and is capped at 5 s. The actual wait is a random value between zero and that limit.

Exponential backoff gives an overloaded or recovering service time to recover. Without it, clients would keep hitting the service at a fixed rate.

Jitter is the random part of the wait. It matters because many clients often fail at the same moment. Without jitter, they would all retry at the same moments too, in synchronised waves. The randomness spreads the retries out. AWS's analysis shows that full jitter (a random wait between zero and the limit) greatly reduces total work and contention.

Do not retry in these cases:

  • Errors that are not transient, such as 400 or 401.
  • Operations that are not idempotent, unless you send an idempotency key. Idempotent means running it twice has the same effect as running it once.
  • When the overall deadline has passed.

Also cap the number of attempts. Do not retry at every layer of a call chain, because the retries multiply.

  • Retry only transient errors, and limit the number of attempts.
  • The wait grows exponentially, up to a cap.
  • Jitter breaks up synchronised waves of retries.
  • Never retry 4xx validation or auth errors, or unsafe calls that are not idempotent.
  • Respect the overall deadline, and retry at only one layer.