Packoff is a minimalist, promised based, exponential backoff lib. Given your current 'retry' attempt, it'll return a promise that you can await
before attempting some operation again.
npm i packoff
The main backoff functions take an options object with the following arguments:
Argument | Default | Description |
---|---|---|
currentAttempt |
none (required) | The number of attempts tried so far. The higher this is, the longer the possible delay |
baseDelayTime |
1000 (1 sec) | This is the base amount of time (in milliseconds used to calculate the backoff delay.) |
jitter |
true | With jitter, your backoff attempt delays will have a smoother curve. You normally want this. Read this for more info. |
cap |
20000 (20 sec) | This caps the max delay of your back off attempts. If you're going to repeatedly retry something over and over, you probably don't want your attempts to end up in the minute time frame... unless you do |
The simplest use case is when you have some async thing you want to try over and over until it works.
import { backoff } from 'packoff';
import riskyBusiness from './async-risky-business';
const tryToDoSomeWork = async () => {
let isDone = false;
let retries = 0;
while (!isDone && retries < 10) {
try {
await riskyBusiness();
console.log('success');
isDone = true;
} catch (e) {
console.log('something went wrong, try again...');
retries += 1;
await backoff({ currentAttempt: retries, baseDelayTime: 1000 });
}
}
};
Optionally, if you want to setup some sort of base configuration, you can do that with setupBackoff.
import { setupBackoff } from 'packoff';
import riskyBusiness from './async-risky-business';
const myBackoff = setupBackoff({ baseDelayTime: 1500, jitter: false });
const tryToDoSomeWork = async () => {
let isDone = false;
let retries = 0;
while (!isDone && retries < 10) {
try {
await riskyBusiness();
console.log('success');
isDone = true;
} catch (e) {
console.log('something went wrong, try again...');
retries += 1;
// Now you just need the attempt count;
await myBackoff(retries);
}
}
};
The helper function tryUntilResolved
is basically the above code wrapped up for you. It'll retry a given async function n (default: 10) times until the async function resolves successfully, backing off in between attempts. (It'll reject if all the attempts fail.)
import { tryUntilResolved } from 'packoff';
import riskyBusiness from './async-risky-business';
const riskyBusinessWithRetry = tryUntilResolved(riskyBusinessWithRetry, {
baseDelayTime: 500,
attemptLimit: 10,
});
const tryToDoSomeWork = async () => {
riskyBusinessWithRetry(og, risky, args);
};
Lastly, when debugging or for logging, it may be useful to know how long your retry is going to wait. There are additional backoffWithMs
and setupBackoffWithMs
functions that return an array instead of a promise. The first element is the delay promise, the second is the ms until that promise resolves;
import { backoffWithMs } from 'packoff';
async function examp() {
const [backoffPromise, ms] = backoffWithMs({
baseDelayTime: 3000,
currentAttempt: 2,
});
console.log(`Waiting ${ms} before continuing!`);
await backoffPromise;
}