retry
withRetry re-runs idempotent requests with replayable bodies on transient statuses and network/timeout errors. Backoff is exponential with full jitter, and Retry-After is honoured.
A caller-cancelled request is never retried, and the backoff wait is itself abortable.
ts
import { corgi } from '@itsy/corgi';
import { withRetry } from '@itsy/corgi/retry';
// number shorthand === { retries: 3 }
const api = corgi.create({ plugins: [withRetry(3)] });
await api.get('/flaky');Works with a client (above), /chonk's retry option, or standalone around native fetch. See the Plugins overview.
Options
ts
withRetry({
retries: 2, // retries AFTER the first attempt (default 2 -> up to 3 tries)
backoff: 300, // base ms; wait for attempt n is random in [0, base * 2**n)
maxDelay: 10_000, // ceiling per wait, and the cap applied to Retry-After
methods: ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'], // idempotent set
statuses: [408, 429, 500, 502, 503, 504], // transient statuses
onRetry: ({ attempt, delay, error, response }) => {
console.log(`retry #${attempt} in ${delay}ms`);
},
});What it will and won't retry
- Methods: only the idempotent set by default.
POST/PATCHare excluded, since replaying them can double-create or double-charge. Override withmethods. - Bodies: only replayable ones (string,
URLSearchParams,Blob,FormData,ArrayBuffer, typed arrays). AReadableStreambody is consumed by the first attempt, so such a request is never retried. - Responses: retried on
statuses(408/429/500/502/503/504 by default). - Errors: a per-attempt
TimeoutError, and genuine networkTypeErrors (DNS/reset/offline). Never a callerAbortError, and never a programmer-errorTypeErrorsuch as "is not a function". Retry-After: when the server sends it (seconds or an HTTP-date) it's used instead of computed backoff, capped atmaxDelay.
Ordering with timeout
withRetry is tagged ORDER.retry (300), which sits outside withTimeout (400), so each attempt gets a fresh deadline and a fired timeout is retried.
ts
// order in the array doesn't matter — corgi sorts by ORDER:
const api = corgi.create({ plugins: [withTimeout(5000), withRetry(3)] });