Promise-based function retry utility. Designed for async/await
.
npm install recaller
example partially stolen from async-retry's example
import recaller, { constantBackoff } from "recaller";
import fetch from "node-fetch";
export default async function fetchSomething() {
return await recaller(
async (bail, attempt) => {
const res = await fetch("https://google.com");
if (403 === res.status) {
// we're not going to retry
return bail(new Error("Unauthorized"));
}
const data = await res.text();
return data.substr(0, 500);
},
{
// default: 2 retries
retries: 10,
// default: no backoff, retry immediately
backoff: constantBackoff(1000),
},
);
}
The code is fully TSDoc'd. See src/index.ts
for documentation of the main functions, listed below:
recaller(fn, opts)
constantBackoff(ms)
fullJitterBackoff(opts)
recaller
doesn't backoff (wait before retrying) by default. To specify backoff, you must give it a backoff function in the options (opts.backoff
).
example:
import recaller, { constantBackoff } from 'recaller'
export default function doSomething () {
return await recaller(async () => {
const res = await fetch('https://google.com')
}, {
// on every failure, wait 5 seconds before retrying
backoff: constantBackoff(5000)
})
}
A backoff function, given an attempt count, returns the next delay to wait in milliseconds.
For example, constantBackoff(ms)
below:
function constantBackoff(ms) {
ms = ms ?? 5000;
return (attempt) => ms;
}
recaller
comes with 5 backoff generator functions, inspired by AWS's exponential backoff blog post.
Use fullJitterBackoff
for most cases, as it generally gives you the best results. You only really have to tweak the base
and cap
with it. See code for more documentation.
constantBackoff(ms)
fullJitterBackoff({base, cap, factor})
the following aren't recommended, and only exist for completeness:
exponentialBackoff({base, cap, factor})
equalJitterBackoff({base, cap, factor})
decorrelatedJitterBackoff({base, cap, times})
You can intercept each retry attempt, by providing a function in opts.onretry
.
import recaller from 'recaller'
export default function doSomething () {
return await recaller(async () => {
const res = await fetch('https://google.com')
}, {
onretry: function (err, attempt, delayTime) {
// Prevent retries; reject the recaller with the last error
if (err instanceof TypeError) throw err
// err is the error of the attempt
// attempt is the attempt #. If the first call failed, then attempt = 1.
// delayTime is how long we will wait before next attempt.
logger.warn(`doSomething attempt ${attempt} failed;
will wait ${delayTime} ms before trying again.
error: ${err}
`)
}
})
}