liveBook · Manning

Retry

As explained in API Design Patterns

A retry is a subsequent attempt to perform an operation after an earlier attempt fails.

A retry is a subsequent attempt to perform an operation after an earlier attempt fails. It is most useful for transient failures caused by overloaded services, scheduled downtime, or rate limits—not for requests that are invalid or permanently forbidden. section 23.3.7 section 29.1

Retry safety depends on what happened before the missing response. A request may never have reached the API, or it may have succeeded while its response was lost. For non-idempotent operations, request deduplication allows a client to retry without executing the operation twice. section 26.1

Apply retries with explicit rules:

  • Classify the failure before retrying. HTTP 500-level errors are more likely to be transient than 400-level errors, but status codes provide guidance rather than certainty. section 29.1
  • Use exponential back-off instead of immediate repeated requests: wait one second, then two, four, eight, and so on. section 29.2.1
  • Bound both the number of retries and the maximum delay, and add random jitter so many clients do not retry simultaneously. section 29.6
  • Honor a Retry-After response header when the API indicates when another attempt is likely to succeed. section 29.2 section 29.6

Retrying a chat-room lookup

A getChatRoomWithRetries function retries a failed GetChatRoom call up to a configured limit. It uses Retry-After when present; otherwise, it waits with jitter, doubles the delay after each failure, caps the delay, and eventually rejects the error. 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 the complete retry implementation, including retry counting, delay caps, jitter, and Retry-After handling. section 29.3.4

How API Design Patterns covers it

How deep it goes
Explains failure classification, deduplication, exponential back-off, jitter, limits, and server-directed timing through an API implementation.
Examples
Uses failed exports, ambiguous API responses, HTTP 429 and 403 errors, and a GetChatRoom implementation.
What it assumes
Assumes HTTP request and response knowledge while teaching transient failures, ambiguous outcomes, and retry timing.
What you can do after
Apply retry policies with failure classification, bounded exponential back-off, jitter, deduplication, and Retry-After handling.
How it connects
Connects retry with idempotency, request deduplication, exponential back-off, jitter, rate limiting, and the Retry-After HTTP header.

Also explained in

Compare how 21 books explain retry →

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.