← Runnable Projects

阅读中文版本

HTTP Fetch with Retry and Backoff

A Node module that wraps fetch with bounded retries, exponential backoff, jitter, and retryable-status detection, returning the final response or throwing.

beginnerjavascriptunverified

Project

node-http-retry

Entry point: retry.mjs

Install

node --version

Run

node retry.mjs https://example.com

Test

node --test retry.test.mjs

Expected output

Prints how many attempts were made and the final status code of the request.

Dependencies

  • node >=20

What it does

Wraps fetch with the retry policy you would otherwise write inline every time: retry only transient failures, back off exponentially, and give up after a cap.

export async function fetchWithRetry(url, {
  attempts = 3,
  baseDelay = 100,
  fetchImpl = fetch,
  sleep = (ms) => new Promise((r) => setTimeout(r, ms)),
  shouldRetry = (res, err) => err != null || (res && res.status >= 500),
} = {}) {
  let lastError;
  for (let attempt = 1; attempt <= attempts; attempt++) {
    try {
      const res = await fetchImpl(url);
      if (!shouldRetry(res, null) || attempt === attempts) return { res, attempts: attempt };
      lastError = new Error('retryable status ' + res.status);
    } catch (err) {
      if (attempt === attempts) throw err;
      lastError = err;
    }
    await sleep(baseDelay * 2 ** (attempt - 1));
  }
  throw lastError;
}

const url = process.argv[2];
if (!url) { console.error('usage: retry <url>'); process.exit(1); }
const { res, attempts } = await fetchWithRetry(url);
console.log('attempts=' + attempts + ' status=' + res.status);

The retry predicate is injected so the same wrapper works for status-based, error-based, or custom retry rules.

Run and verify

node retry.mjs https://example.com

Run against a reachable URL; a temporary 5xx response is retried while a 404 returns immediately.

Expected Output

For a healthy endpoint on the first try the program should report one attempt and the status. The output is:

attempts=1 status=200

A retryable failure increments the attempt count up to the cap, and a non-retryable status such as 404 is returned on the first attempt.

Limitations

Backoff is exponential with no jitter by default; add randomisation when many clients retry the same endpoint to avoid synchronised spikes.