Skip to content

Commit

Permalink
Add retries on ECONNRESET (#164)
Browse files Browse the repository at this point in the history
* Add retries on ECONNRESET

* Share retry predicate with both http methods

* Add retry conditions for various other error codes
  • Loading branch information
timhaines authored and Wil Wilsman committed Dec 11, 2019
1 parent bc4994e commit f5f1409
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
19 changes: 13 additions & 6 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,20 @@ const fs = require('fs');

require('dotenv').config();

const RETRY_ERROR_CODES = ['ECONNRESET', 'ECONNREFUSED', 'EPIPE', 'EHOSTUNREACH', 'EAI_AGAIN'];
const JSON_API_CONTENT_TYPE = 'application/vnd.api+json';
const CONCURRENCY = 2;

function retryPredicate(err) {
if (err.statusCode) {
return err.statusCode >= 500 && err.statusCode < 600;
} else if (err.error && !!err.error.code) {
return RETRY_ERROR_CODES.includes(err.error.code);
} else {
return false;
}
}

class Resource {
constructor(options) {
if (!options.resourceUrl) {
Expand Down Expand Up @@ -94,9 +105,7 @@ class PercyClient {
interval: 50,
max_tries: 5,
throw_original: true,
predicate: function(err) {
return err.statusCode >= 500 && err.statusCode < 600;
},
predicate: retryPredicate,
});
}

Expand All @@ -117,9 +126,7 @@ class PercyClient {
interval: 50,
max_tries: 5,
throw_original: true,
predicate: function(err) {
return err.statusCode >= 500 && err.statusCode < 600;
},
predicate: retryPredicate,
});
}

Expand Down
58 changes: 57 additions & 1 deletion test/main-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ describe('PercyClient', function() {
done(err);
});
});

it('retries on 500s', async () => {
let mock = nock('https://localhost')
.get('/foo')
.reply(500, {success: false})
.get('/foo')
.reply(201, {success: true});

let response = await percyClient._httpGet('https://localhost/foo');
assert.equal(response.statusCode, 201);
assert.deepEqual(response.body, {success: true});
mock.done();
});

['ECONNRESET', 'ECONNREFUSED', 'EPIPE', 'EHOSTUNREACH', 'EAI_AGAIN'].forEach(code => {
it(`retries on ${code}`, async () => {
let mock = nock('https://localhost')
.get('/foo')
.replyWithError({code})
.get('/foo')
.reply(201, {success: true});

let response = await percyClient._httpGet('https://localhost/foo');
assert.equal(response.statusCode, 201);
assert.deepEqual(response.body, {success: true});
mock.done();
});
});
});

describe('_httpPost', function() {
Expand All @@ -52,7 +80,7 @@ describe('PercyClient', function() {
assert.equal(this.req.headers['authorization'], `Token token=test-token`);
assert.equal(requestBody, JSON.stringify(requestData));
let responseBody = {success: true};
return [201, responseBody];
return responseBody;
};
nock('https://localhost')
.post('/foo')
Expand All @@ -69,6 +97,34 @@ describe('PercyClient', function() {
done(err);
});
});

it('retries on 500s', async () => {
let mock = nock('https://localhost')
.post('/foo')
.reply(500, {success: false})
.post('/foo')
.reply(201, {success: true});

let response = await percyClient._httpPost('https://localhost/foo', {foo: 123});
assert.equal(response.statusCode, 201);
assert.deepEqual(response.body, {success: true});
mock.done();
});

['ECONNRESET', 'ECONNREFUSED', 'EPIPE', 'EHOSTUNREACH', 'EAI_AGAIN'].forEach(code => {
it(`retries on ${code}`, async () => {
let mock = nock('https://localhost')
.post('/foo')
.replyWithError({code})
.post('/foo')
.reply(201, {success: true});

let response = await percyClient._httpPost('https://localhost/foo', {foo: 123});
assert.equal(response.statusCode, 201);
assert.deepEqual(response.body, {success: true});
mock.done();
});
});
});

describe('token', function() {
Expand Down

0 comments on commit f5f1409

Please sign in to comment.