How to implement retry logic with async operations

· Category: Node.js

Short answer

Wrap your async operation in a loop that catches errors, waits using an exponential backoff delay, and retries up to a maximum number of attempts.

Steps

  1. Create an async function that accepts the operation, max retries, and delay.
  2. Loop from 0 to max retries.
  3. Inside the loop, try to execute the operation.
  4. On failure, wait with await new Promise(r => setTimeout(r, delay));.
  5. Increase the delay exponentially and throw if the final attempt fails.
async function retry(fn, maxAttempts = 3, delay = 1000) {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === maxAttempts - 1) throw err;
      await new Promise(r => setTimeout(r, delay * Math.pow(2, i)));
    }
  }
}

Tips

  • Use a jitter randomization to prevent thundering herd problems when many clients retry simultaneously.
  • Only retry idempotent operations like GET requests, not POST requests that mutate state.

Common issues

  • Not capping the maximum delay can lead to unacceptably long waits.
  • Retrying on non-transient errors like 400 Bad Request wastes resources.