Browse Source

Add exponential retry on network errors

Closes #98
http2
Vsevolod Strukchinsky 9 years ago
parent
commit
6c59ce8b34
  1. 12
      index.js
  2. 10
      readme.md
  3. 2
      test/http.js
  4. 31
      test/retry.js

12
index.js

@ -19,11 +19,17 @@ var nodeStatusCodes = require('node-status-codes');
var isPlainObj = require('is-plain-obj');
var parseJson = require('parse-json');
function backoff(iter) {
var noise = Math.random() * 1000;
return (1 << iter) * 1000 + noise;
}
function requestAsEventEmitter(opts) {
opts = opts || {};
var ee = new EventEmitter();
var redirectCount = 0;
var retryCount = 0;
var get = function (opts) {
var fn = opts.protocol === 'https:' ? https : http;
@ -49,6 +55,11 @@ function requestAsEventEmitter(opts) {
ee.emit('response', typeof unzipResponse === 'function' ? unzipResponse(res) : res);
}).once('error', function (err) {
if (retryCount < opts.retries) {
setTimeout(get, backoff(retryCount++), opts);
return;
}
ee.emit('error', new got.RequestError(err, opts));
});
@ -194,6 +205,7 @@ function normalizeArguments(url, opts) {
opts = objectAssign(
{protocol: 'http:', path: ''},
url,
{retries: 5},
opts
);

10
readme.md

@ -12,7 +12,7 @@
A nicer interface to the built-in [`http`](http://nodejs.org/api/http.html) module.
It supports following redirects, promises, streams, automagically handling gzip/deflate and some convenience options.
It supports following redirects, promises, streams, retries, automagically handling gzip/deflate and some convenience options.
Created because [`request`](https://github.com/mikeal/request) is bloated *(several megabytes!)*.
@ -111,6 +111,14 @@ Type: `number`
Milliseconds after which the request will be aborted and an error event with `ETIMEDOUT` code will be emitted.
###### retries
Type: `number`
Default: `5`
Number of request retries when network errors happens.
##### callback(error, data, response)
Function to be called when error or data are received. If omitted, a promise will be returned.

2
test/http.js

@ -69,7 +69,7 @@ test('http - buffer on encoding === null', t => {
});
test('http - timeout option', t => {
got(`${s.url}/404`, {timeout: 1}, err => {
got(`${s.url}/404`, {timeout: 1, retries: 1}, err => {
t.is(err.code, 'ETIMEDOUT');
t.end();
});

31
test/retry.js

@ -0,0 +1,31 @@
import test from 'ava';
import got from '../';
import {createServer} from './_server';
const s = createServer();
s.on('/long', () => {});
let knocks = 0;
s.on('/knock-twice', (req, res) => {
if (knocks++ === 1) {
res.end('who`s there?');
}
});
test.before('retry - setup', t => {
s.listen(s.port, () => t.end());
});
test('retry - timeout errors', t => {
got(`${s.url}/knock-twice`, {timeout: 1000}, (err, data) => {
t.ifError(err);
t.is(data, 'who`s there?');
t.end();
});
});
test.after('error - cleanup', t => {
s.close();
t.end();
});
Loading…
Cancel
Save