retry
Problem
A network call or external API is flaky and fails occasionally. You need automatic retries with configurable delay and the ability to cancel early or skip certain error types.
Solution
Use retry(fn, options) to re-run an async function up to times attempts. The callback receives an AbortSignal that fires when a per-attempt timeout expires or the external signal is aborted.
ts
import { retry, backoff } from '@vielzeug/arsenal';
const data = await retry((signal) => fetch('/api/health', { signal }).then((r) => r.json()), {
times: 4,
timeout: 5_000,
delay: (failureIndex) => backoff(failureIndex), // 1s, 2s, 4s, 8s
shouldRetry: (err, failureIndex) => {
// failureIndex is 0-based: 0 = first failure
// NOT called on the final exhausting attempt
return failureIndex < 3 && !(err instanceof TypeError);
},
});Basic usage
ts
import { retry } from '@vielzeug/arsenal';
const result = await retry(() => fetch('/api').then((r) => r.json()), { times: 3, delay: 250 });With external cancellation
ts
import { retry } from '@vielzeug/arsenal';
const controller = new AbortController();
const result = await retry((signal) => fetch('/api/data', { signal }).then((r) => r.json()), {
times: 3,
signal: controller.signal,
});
controller.abort(); // cancels retries mid-flightPitfalls
shouldRetryis not called on the final (exhausting) attempt — it only guards intermediate retries.failureIndexis 0-based: index0is the first failure, index1is the second, and so on.- When a
timeoutis set, thesignalpassed tofnfires aftertimeoutms — pass it tofetchor other cancellable APIs. - On exhaustion, the last error is re-thrown unchanged.