Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Commit

Permalink
initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
rauchg committed Oct 14, 2017
0 parents commit 93df2f8
Show file tree
Hide file tree
Showing 6 changed files with 2,667 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
45 changes: 45 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
let fetch;

try {
fetch = require('node-fetch');
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND' && /node-fetch/.test(err.message)) {
console.error('Could not find peer dependency `node-fetch`. ' +
'Make sure it is installed: `yarn add node-fetch`');
}
throw err;
}

const retry = require('async-retry');
const debug = require('debug')('fetch-retry');

// retry settings
const MIN_TIMEOUT = 10;
const MAX_RETRIES = 3;
const FACTOR = 5;

const fetchRetry = (url, opts = {}, retryOpts) => (
retry(async (bail, attempt) => {
const {method = 'GET'} = opts;
try {
// this will be retried
const res = await fetch(url, opts);
debug('status %d', res.status);
if (res.status >= 500 && res.status < 600) {
throw err;
} else {
return res;
}
} catch (err) {
debug(`${method} ${url} error (${res.status}). ${attempt < MAX_RETRIES ? 'retrying' : ''}`, err);
throw err;
}
}, retryOpts || {
// timeouts will be [ 10, 50, 250 ]
minTimeout: MIN_TIMEOUT,
retries: MAX_RETRIES,
factor: FACTOR
})
);

module.exports = fetchRetry;
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@zeit/fetch-retry",
"devDependencies": {
"jest": "^21.2.1",
"node-fetch": "^1.7.3"
},
"dependencies": {
"async-retry": "^1.1.3"
},
"scripts": {
"test": "jest test"
}
}
47 changes: 47 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# fetch-retry

A layer on top of `fetch` (via [node-fetch](https://www.npmjs.com/package/node-fetch)
with sensible defaults for retrying to prevent common errors.

## How to use

`fetch-retry` is a drop-in replacement for `fetch`:

```js
const fetch = require('@zeit/fetch-retry');
module.exports = async () => {
const res = await fetch('http://localhost:3000')
console.log(res.status);
}
```

Make sure to `yarn add fetch-retry` in your main package.

The third optional parameter is custom [retry options](https://github.com/zeit/async-retry)
passed to `async-retry`.

## Rationale

Some errors are very common in production (like the underlying `Socket`
yielding `ECONNRESET`), and can easily and instantly be remediated
by retrying.

The default behavior of `fetch-retry` is to attempt retries **10**, **50**
and **250** milliseconds (a total of 3 retires) after
a *network error* or *5xx* error occur.

The idea is to provide a sensible default: most applications should
continue to perform correctly with a worst case scenario of a given
request having an additional 250ms overhead.

On the other hand, most applications that use `fetch-retry` instead of
vanilla `fetch` should see lower rates of common errors and fewer 'glitches'
in production.

## Tests

To run rests, execute

```console
npm test
```
29 changes: 29 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const {createServer} = require('http');
const retryFetch = require('./index');

test('retries upon 500', async () => {
let i = 0
const server = createServer((req, res) => {
if (i++ < 2) {
res.writeHead(500);
res.end();
} else {
res.end('ha');
}
});

return new Promise((resolve, reject) => {
server.listen(async () => {
const {port} = server.address();
try {
const res = await retryFetch(`http://127.0.0.1:${port}`);
expect(await res.text()).toBe('ha');
server.close();
resolve();
} catch (err) {
reject(err);
}
});
server.on('error', reject);
});
});
Loading

0 comments on commit 93df2f8

Please sign in to comment.