@chey.dev/retry
v1.0.8
Published
simple class to retry functions
Readme
@chey.dev/retry
A lightweight retry utility for transient async failures. It wraps a callback in a retry loop with exponential backoff and jitter so brief network, service, or temporary runtime issues do not fail immediately.
Installation
npm install @chey.dev/retryUsage
import { Retry } from "@chey.dev/retry";
const result = await new Retry().execute(async () => {
const response = await fetch("https://example.com/api");
if (!response.ok) {
throw new Error("Request failed");
}
return response.json();
});API
new Retry(options?)
Creates a retry controller.
const retry = new Retry({
maxRetries: 4,
delay: 500,
maxTimeout: 10_000,
outputFunction: ({ retriesLeft, delay, error }) => {
console.log(`Retrying in ${delay}ms; ${retriesLeft} retries left.`, error);
},
});Options
The constructor uses these defaults when no options are provided:
| Option | Default | Description |
| --- | ---: | --- |
| maxRetries | 5 | Maximum number of retries after the initial attempt. With the default value, the operation can retry up to 5 times before failing. |
| delay | 1000 | Initial backoff delay in milliseconds before the first retry. |
| maxTimeout | 25000 | Maximum allowed delay cap in milliseconds to stop runaway backoff. |
| outputFunction | null | Optional callback invoked before every retry with the retry status. |
outputFunction callback
Use outputFunction to observe retry status without handling logging inside the callback being retried. It receives an object with these properties:
| Property | Description |
| --- | --- |
| requestID | Unique ID shared by all attempts for the current Retry instance. |
| delay | Delay, in milliseconds, before the next retry. |
| retriesLeft | Number of retries remaining after the current failed attempt. |
| error | Error thrown or rejected by the failed callback attempt. |
const retry = new Retry({
outputFunction: ({ requestID, delay, retriesLeft, error }) => {
console.log(`[${requestID}] Retrying in ${delay}ms.`);
console.log(`${retriesLeft} retries remaining:`, error.message);
},
});execute(callback)
Runs the provided async callback and retries it when it throws or rejects.
await retry.execute(async () => {
return doSomethingRisky();
});Behavior
- Retries on thrown errors and rejected promises.
- Uses exponential backoff with a small random jitter added to each delay.
- Stops retrying when the retry budget is exhausted.
- Throws an error if the delay exceeds the configured
maxTimeout. - When retries are exhausted,
execute()rejects with an error containing the last callback error. - When the backoff exceeds
maxTimeout,execute()rejects with a timeout error. Both terminal failures must be caught by the caller.
Handling terminal failures
Always wrap execute() in a try/catch. The retry operation rejects when it either exhausts its retry budget or reaches the configured timeout.
import { Retry } from "@chey.dev/retry";
const retry = new Retry({ maxRetries: 3, delay: 750, maxTimeout: 15_000 });
try {
const data = await retry.execute(async () => {
const response = await fetch("https://example.com/api");
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
return response.json();
});
console.log(data);
} catch (error) {
// Handle the last retry error or the timeout error here.
console.error("Retry failed:", error);
}Example
import { Retry } from "@chey.dev/retry";
const retry = new Retry({ maxRetries: 3, delay: 750, maxTimeout: 15_000 });
try {
const data = await retry.execute(async () => {
// Example: retry a flaky async call
throw new Error("temporary failure");
});
console.log(data);
} catch (error) {
console.error("Retry failed:", error);
}Notes
This package is designed for transient failures in async workflows. It is intentionally small and focused, so it does not manage concurrency, circuit breaking, or custom retry policies beyond the built-in exponential backoff behavior.
