Back to results for “Async Patterns”
Node.js › Async Patterns

How do you implement a retry-with-exponential-backoff pattern for a flaky async operation in Node.js?

Intermediate

Answer

Exponential backoff retries a failed operation with progressively longer delays between attempts (typically doubling each time, often with added random 'jitter' to avoid multiple clients retrying in lockstep) rather than retrying immediately or at a fixed interval, reducing load on an already-struggling downstream service while still recovering automatically once it becomes available again.
async function retryWithBackoff(fn, maxRetries = 5, baseDelay = 200) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxRetries - 1) throw err;
      const delay = baseDelay * 2 ** attempt + Math.random() * 100;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}
Real-world example A payment-service client wraps its API calls in a retryWithBackoff helper so that transient network blips or brief rate-limiting from the payment provider are automatically retried up to five times with increasing delays, rather than immediately failing the customer's checkout on the very first transient error.

Common follow-ups: Which types of errors should actually be retried versus failed immediately (like a 400 Bad Request versus a 503 Service Unavailable)?;How does adding jitter specifically help prevent a 'thundering herd' problem?