typestar

Retry with backoff in JavaScript

Try again, waiting longer each time, and give up eventually.

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function retry(work, { attempts = 4, base = 5 } = {}) {
  let lastError;
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      return await work(attempt);
    } catch (error) {
      lastError = error;
      if (attempt === attempts) break;
      await sleep(base * 2 ** (attempt - 1));
    }
  }
  throw new Error(`failed after ${attempts} attempts`, { cause: lastError });
}

async function main() {
  const value = await retry(async (attempt) => {
    if (attempt < 3) throw new Error(`attempt ${attempt} failed`);
    return "succeeded";
  });
  console.log(value);

  const failed = await retry(async () => {
    throw new Error("always");
  }, { attempts: 2 }).catch((e) => e);
  console.log(failed.message, "|", failed.cause.message);
}

main();

How it works

  1. The delay doubles, which is what backoff means.
  2. Only retry what is worth retrying.
  3. Attach the last error as the cause when giving up.

Keywords and builtins used here

The run, in numbers

Lines
30
Characters to type
787
Tokens
232
Three-star pace
110 tpm

At the three-star pace of 110 tokens a minute, this run takes about 127 seconds.

Type this snippet

Step 3 of 4 in Canceling & limiting, step 17 of 19 in Promises & async.

← Previous Next →

Retry with backoff in other languages