Skip to content

Commit

Permalink
fixups, change default to something more sane
Browse files Browse the repository at this point in the history
as they say, 3rd time's the charm
  • Loading branch information
SEAPUNK committed Apr 7, 2024
1 parent 3a7e963 commit e23e4ce
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 37 deletions.
57 changes: 28 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

Promise-based function retry utility. Designed for `async/await`.

**Requires node v4 or above**

`npm install recaller`

- [usage](#usage)
Expand All @@ -22,7 +20,7 @@ Promise-based function retry utility. Designed for `async/await`.
_example partially stolen from [async-retry](https://github.com/zeit/async-retry)'s example_

```js
import recaller from "recaller";
import recaller, { constantBackoff } from "recaller";
import fetch from "node-fetch";

export default async function fetchSomething() {
Expand All @@ -38,37 +36,32 @@ export default async function fetchSomething() {
const data = await res.text();
return data.substr(0, 500);
},
{ retries: 5 },
{
// default: 2 retries
retries: 10,
// default: no backoff, retry immediately
backoff: constantBackoff(1000),
},
);
}
```

## api

`recaller(fn, opts)`

Calls provided (async or regular) function, and retries on failure.

`fn` is called with two arguments:

- `bail(err)` Stops and rejects the retryer's promise with given error.
- Note that this does not stop execution, so you have to return manually, allowing you to do some cleanup before returning
- `attempt` Current attempt. First call to function = attempt 1.
The code is fully TSDoc'd. See `src/index.ts` for documentation of the main functions, listed below:

`opts` is an object, with the following properties:

- `opts.retries` (default `10`) How many times to retry before giving up, and rejecting with the error.
- `opts.backoff` (default `null`) Backoff generator to use. If null, there is no backoff, and on fail, the function is retried immediately. See: [backoffs](#backoffs)
- `opts.onretry` (default `null`) Retry event handler. See: [handling retries](#handling-retries)
- `recaller(fn, opts)`
- `constantBackoff(ms)`
- `fullJitterBackoff(opts)`

## backoffs

`recaller` doesn't backoff (wait before retrying) by default. To specify backoff, you must give it a "backoff generator" in the options (`opts.backoff`).
`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:

```js
import recaller, {constantBackoff} from 'recaller'
import recaller, { constantBackoff } from 'recaller'

export default function doSomething () {
return await recaller(async () => {
Expand All @@ -80,26 +73,32 @@ export default function doSomething () {
}
```

A backoff generator is a function that returns the next delay to wait in milliseconds. For example, the full `constantBackoff(ms)` generator is below:
A backoff function, given an attempt count, returns the next delay to wait in milliseconds.
For example, `constantBackoff(ms)` below:

```js
function constantBackoff(ms) {
ms = ms || 5000;
ms = ms ?? 5000;
return (attempt) => ms;
}
```
`recaller` comes with 5 backoff generator functions, inspired by [AWS's exponential backoff blog post](https://www.awsarchitectureblog.com/2015/03/backoff.html).
- [`constantBackoff(ms)`](https://github.com/SEAPUNK/recaller/blob/56f9d7b29a0459e1c4f4d40b1de9cd53be589405/lib/index.js#L86-L97)
- [`exponentialBackoff({base, cap, factor})`](https://github.com/SEAPUNK/recaller/blob/56f9d7b29a0459e1c4f4d40b1de9cd53be589405/lib/index.js#L99-L123)
- [`fullJitterBackoff({base, cap, factor})`](https://github.com/SEAPUNK/recaller/blob/56f9d7b29a0459e1c4f4d40b1de9cd53be589405/lib/index.js#L125-L136)
- [`equalJitterBackoff({base, cap, factor})`](https://github.com/SEAPUNK/recaller/blob/56f9d7b29a0459e1c4f4d40b1de9cd53be589405/lib/index.js#L138-L153)
- [`decorrelatedJitterBackoff({base, cap, times})`](https://github.com/SEAPUNK/recaller/blob/56f9d7b29a0459e1c4f4d40b1de9cd53be589405/lib/index.js#L154-L178)
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})`
## handling retries
You can intercept each retry attempt, by providing a middleware function in `opts.onretry`.
You can intercept each retry attempt, by providing a function in `opts.onretry`.
```js
import recaller from 'recaller'
Expand All @@ -118,7 +117,7 @@ export default function doSomething () {

logger.warn(`doSomething attempt ${attempt} failed;
will wait ${delayTime} ms before trying again.
error: ${err.stack}
error: ${err}
`)
}
})
Expand Down
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export type RecallerOptions = {
* How many times to retry before giving up.
* With `retries: 1`, the function will be called twice total before giving up.
*
* @defaultValue `10`
* @defaultValue `2`
*/
retries?: number;
/**
Expand Down Expand Up @@ -138,7 +138,7 @@ export default async function recaller(fn: RecallerFn, opts?: RecallerOptions) {
if (_opts.onretry && typeof _opts.onretry !== "function")
throw new Error("onretry handler is not a function");

const retries = _opts.retries ?? 10;
const retries = _opts.retries ?? 2;

let bailed = false;
let attempt = 0;
Expand Down Expand Up @@ -209,19 +209,19 @@ export type ExponentialBackoffOpts = {
/**
* Base delay in ms. Used as initial delay (before applying jitter), and to calculate future values.
*
* @defaultValue 1000
* @defaultValue `1000`
*/
base?: number;
/**
* Maximum delay in ms.
*
* @defaultValue 60000
* @defaultValue `60000`
*/
cap?: number;
/**
* `uncappedDelay = base * (factor ^ (attempt - 1))`
*
* @defaultValue 2
* @defaultValue `2`
*/
factor?: number;
};
Expand Down Expand Up @@ -313,19 +313,19 @@ export type DecorrelatedJitterBackoffOpts = {
/**
* Base delay in ms. Delay will not be lower than this.
*
* @defaultValue 1000
* @defaultValue `1000`
*/
base?: number;
/**
* Maximum delay in ms.
*
* @defaultValue 60000
* @defaultValue `60000`
*/
cap?: number;
/**
* Multiplier for the next delay based on last delay time.
*
* @defaultValue 3
* @defaultValue `3`
*/
times?: number;
};
Expand Down

0 comments on commit e23e4ce

Please sign in to comment.