-
Notifications
You must be signed in to change notification settings - Fork 0
Services Retry
io.retry retries failed requests with exponential backoff, but only when it is safe to do so: idempotent verbs retry automatically, while a bare POST does not.
import io from 'double-meh';
io.retry.attach();
const data = await io.get('https://example.com/r', null, {retries: 3});
// a 5xx / 429 / network error is retried up to 3 times, then the last result standsRetries are off unless you pass retries (a number >= 1). What counts as a failure is a network error, any 5xx, or 429.
GET, HEAD, OPTIONS, PUT, and DELETE are idempotent and retry automatically. PATCH retries only with ifMatch or as: 'merge-patch'. A bare POST is not retried; it must carry an idempotencyKey or If-None-Match: * (ifNoneMatch: '*') to unlock retry. Set retry: true to force retry regardless, or retry: false to disable it.
// bare POST: not retried even with retries set
await io.post('https://example.com/p', {a: 1}, {retries: 3, ignoreBadStatus: true});
// POST with an idempotency key: retried, same key reused across attempts
await io.post('https://example.com/p', {a: 1}, {retries: 1, idempotencyKey: true});When a failed response carries a Retry-After header (delta-seconds or an HTTP date), that delay is used for the next attempt instead of the backoff timer.
await io.get('https://example.com/rate-limited', null, {retries: 2});
// a 429 with `Retry-After: 5` waits ~5s before retryingIf a DELETE succeeds on the server but its response is lost and a retry then returns 404, the resource is already gone — so a 404 on any attempt after the first is rewritten to 204 No Content.
const env = await io.full.delete('https://example.com/d', null, {retries: 3});
env.status; // 204 when a retried DELETE hits 404-
retries— maximum retry attempts (required to enable retry). -
retry—trueforces retry,falsedisables it. -
initDelay— first backoff delay in ms (defaultio.retry.initDelay, 100). UseinitDelay: 0for immediate retries.
await io.get('https://example.com/r', null, {retries: 3, initDelay: 200});io.retry.nextDelay(delay, attempt, options) computes the next backoff from the current one; the default doubles it and caps at 5s. Replace it to change the curve.
io.retry.nextDelay = delay => Math.min(delay * 3, 10_000);Requests with a streaming (ReadableStream) body are not retried, since the body cannot be replayed.
io.retry.attach() installs the service (setting io.retry.isActive); io.retry.detach() removes it. Both return io.
io.retry.attach();
io.retry.detach();Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook