Glossary / Retry strategies

Retry strategies

A retry strategy decides whether and when to repeat a failed operation. Retries can improve resilience for transient faults, but can amplify overload, duplicate side effects, and increase latency. A sound design classifies failures, bounds attempts and total time, applies backoff, respects cancellation and server guidance, and requires idempotency where repeating may commit effects.

Policy design

Retry only errors likely to be transient (selected network failures, throttling, or some server errors), not validation/authentication failures. Set a maximum attempt count and an overall deadline; attempt count alone may allow an unexpectedly long operation. Use exponential backoff with jitter and honor Retry-After when appropriate. Avoid retrying at every layer, which multiplies attempts (for example 3 retries in three nested layers can yield many downstream calls).

async function retry(operation, { attempts, signal }) {
  for (let n = 0; ; n++) {
    signal?.throwIfAborted();
    try { return await operation({ signal }); }
    catch (error) {
      if (n + 1 >= attempts || !isTransient(error)) throw error;
      await delay(backoff(n), { signal });
    }
  }
}

The helper must classify errors carefully, support abort during delay, and ensure operation is safe to repeat. Retries should be observable with attempt count, reason, and final outcome, without logging secrets.

Interview questions

  1. What failures should be retried? Only transient failures likely to succeed later, under a bounded policy.
  2. Why not retry every error? Permanent errors waste capacity and retries can amplify outages.
  3. Why coordinate retry layers? Nested retries multiply requests and latency.
  4. What must hold for a side-effecting retry? Idempotency or deduplication semantics.

References