liveBook · Manning

Exponential backoff

As explained in API Design Patterns

Exponential backoff is a retry strategy that increases the delay between successive attempts, typically by a multiplicative factor.

Exponential backoff spaces retry attempts by increasing the delay after each failure, commonly doubling it: 1, 2, 4, 8, 16, and 32 seconds. It gives an API time to recover when the client cannot observe the server’s internal state. section 29.2.1

Use it for transient or time-related failures, not automatically for permanent failures. A request returning HTTP 429 may be retriable, while HTTP 403 is generally unsafe to retry. section 29.6

A practical retry policy should:

  • Bound the retry count and maximum delay so a request eventually fails instead of waiting indefinitely. section 29.3.2
  • Add random jitter to each delay so many clients do not retry simultaneously and overload the service again. section 29.3.2
  • Honor server-provided timing when available; a Retry-After value overrides the client’s normal backoff delay. section 29.2.2 section 29.3.4
  • Treat the policy as client-enforced: the server can recommend retry behavior but cannot control whether clients follow it. section 29.4

Retrying a chat-room lookup

A getChatRoomWithRetries function can begin with a one-second delay, double the backoff after each failed request, stop after a configured retry count, cap the delay at 32 seconds, and add up to one second of jitter. The final policy first uses Retry-After when the response supplies it; otherwise it uses jittered exponential backoff. section 29.3.2 section 29.3.4

Listing 29.5 Final API definition
async function getChatRoomWithRetries(
    id: string, maxDelayMs = 32000, maxRetries = 10): Promise<ChatRoom> {
  return new Promise<ChatRoom>(async (resolve, reject) => {
    let retryCount = 0;
    let delayMs = 1000;
    while (true) {
      try {
        return resolve(GetChatRoom({ id }));
      } catch (e) {
        if (retryCount++ > maxRetries) return reject(e);
        await new Promise((resolve) => {
          let actualDelayMs;
          if ('Retry-After' in e.response.headers) {
            actualDelayMs = Number(
              e.response.headers['Retry-After']) * 1000;
          } else {
            actualDelayMs = delayMs + (Math.random() * 1000);
          }
          return setTimeout(resolve, actualDelayMs);
        });
        delayMs *= 2;
        if (delayMs > maxDelayMs) delayMs = maxDelayMs;
      }
    }
  });
}

Inspect a complete TypeScript-style retrieval function combining retry limits, delay caps, jitter, and server-directed timing. section 29.3.4

How API Design Patterns covers it

How deep it goes
Explains doubling delays, retry caps, delay caps, jitter, and Retry-After, but leaves retry eligibility as a separate decision.
Examples
Demonstrates chat-room retrieval with doubling delays, bounded retries, jitter, and a Retry-After response header.
What it assumes
Assumes familiarity with failed API requests and asynchronous calls while teaching retry timing from the basic doubling rule.
What you can do after
Apply it by implementing bounded, jittered API retries that honor server-provided retry timing.
How it connects
Connects exponential backoff with retries, rate limiting, Retry-After, stampeding herds, HTTP 429, and long-running-operation polling.

Also explained in

Compare how 8 books explain exponential backoff →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of API Design Patterns. The section links point to the parts of the book it draws on.