A TypeScript utility library that provides configurable retry logic with backoff for any async function.
# pnpm
pnpm add @aecomet/backoff-util
# npm
npm install @aecomet/backoff-util
# yarn
yarn add @aecomet/backoff-utilRetries up to 10 times with exponential backoff (base delay 10ms, max 1000ms).
import { Utility } from '@aecomet/backoff-util';
const utility = new Utility();
const result = await utility.backoff(async () => {
return await fetchSomething();
});import { Utility } from '@aecomet/backoff-util';
const utility = new Utility({
retryCount: 5,
minDelay: 100,
maxDelay: 2000,
delay: 'linear'
});
const result = await utility.backoff(async () => {
return await fetchSomething();
});| Option | Type | Default | Description |
|---|---|---|---|
retryCount |
number |
10 |
Maximum number of retry attempts |
minDelay |
number |
10 |
Base delay value (ms) used in the backoff formula |
maxDelay |
number |
1000 |
Upper bound for the computed delay (ms) |
delay |
'exponential' | 'linear' | 'fixed' |
'exponential' |
Delay calculation strategy, or a custom function |
factor |
number |
2 |
Multiplier for exponential delay (minDelay * factor^attempt) |
jitter |
'full' | 'none' |
'full' |
Jitter strategy, or a custom function |
shouldRetry |
(ctx: BackoffContext) => boolean |
retry always | Return false to stop retrying immediately |
onRetry |
(ctx: BackoffContext) => void |
console.warn |
Called on each retry for logging or side effects |
timeoutMs |
number |
none | Total elapsed time limit (ms); throws when exceeded |
signal |
AbortSignal |
none | Cancels the retry loop when the signal is aborted |
import { Utility } from '@aecomet/backoff-util';
const controller = new AbortController();
const utility = new Utility({
retryCount: 5,
minDelay: 100,
maxDelay: 2000,
delay: 'linear',
factor: 3,
jitter: 'none',
shouldRetry: (ctx) => {
return ctx.error instanceof Error && ctx.error.message.startsWith('5');
},
onRetry: (ctx) => {
console.log(`Retry #${ctx.attempt}:`, ctx.error);
},
timeoutMs: 10000,
signal: controller.signal
});
const result = await utility.backoff(async () => fetchSomething());You can inject custom functions for full control:
import { Utility } from '@aecomet/backoff-util';
// Custom exponential delay
const utility = new Utility({
delay: (ctx) => Math.min(100 * Math.pow(2, ctx.attempt), 5000),
jitter: (delay) => delay * (0.5 + Math.random())
});Callbacks receive a context object:
| Field | Type | Description |
|---|---|---|
attempt |
number |
Current attempt index (0-based) |
error |
unknown |
The error that caused the retry |
elapsed |
number |
Total elapsed time since the first call (ms) |
More example code is available in the example/ directory.
pnpm build
node example/sample.mjs
node example/sampleWithConfig.mjs
node example/sampleWithAxios.mjs
node example/sampleWithShouldRetry.mjs
node example/sampleWithOnRetry.mjs
node example/sampleWithTimeout.mjs
node example/sampleWithStrategy.mjs
node example/sampleWithAbort.mjs- Node.js
26.3.0(see.node-version) - pnpm
11
# Build
pnpm build
# Run tests
pnpm test
# Run tests with UI
pnpm test -- --ui
# Link locally for testing in another project
pnpm link -g .See docs/architecture.md for project structure and design details.
If you are upgrading from v1, see the migration guide.