request-retry - HTTP(s) request retry on recoverable errors.
When the connection fails with one of ECONNRESET
, ENOTFOUND
, ESOCKETTIMEDOUT
, ETIMEDOUT
, ECONNREFUSED
, EHOSTUNREACH
, EPIPE
, EAI_AGAIN
or when an HTTP 5xx or 429 error occurrs, the request will automatically be re-attempted as these are often recoverable errors and will go away on retry.
❤️ Shameless plug
Installation
Install with npm.
npm install --save requestretry
Usage
Request-retry is a drop-in replacement for request but adds two new options maxAttempts
and retryDelay
. It also adds one property to the response (or the error object, upon a network error), attempts
. It supports callbacks or promises.
With callbacks
var request = require('requestretry');
request({
url: 'https://api.domain.com/v1/a/b',
json: true,
maxAttempts: 5,
retryDelay: 5000,
retryStrategy: request.RetryStrategies.HTTPOrNetworkError
}, function(err, response, body){
if (response) {
console.log('The number of request attempts: ' + response.attempts);
}
});
With promises
When you're using promises, you can pass the two following options:
fullResponse
(default true) - To resolve the promise with the full response or just the bodypromiseFactory
(default whenjs) - A function to allow the usage of a different promise implementation library
request({
url: 'https://api.domain.com/v1/a/b',
json: true,
fullResponse: true
})
.then(function (response) {
})
.catch(function(error) {
})
Using promiseFactory
option to use a different promise implementation library
function customPromiseFactory(resolver) {
return require('when').promise(resolver);
var Promise = require('rsvp').Promise;
return new Promise(resolver);
}
request({
url: 'https://api.domain.com/v1/a/b',
json: true,
promiseFactory: customPromiseFactory
})
.then(function (response) {
})
.catch(function(error) {
})
How to define your own retry strategy
A retry strategy let you specify when request-retry should retry a request
function myRetryStrategy(err, response, body, options){
return !!err || response.statusCode === 502;
}
function myRetryStrategy(err, response, body, options){
options.url = 'new url';
return {
mustRetry: !!err || response.statusCode === 502,
options: options,
}
}
async function myRetryStrategy(err, response, body, options){
let token = await getNewApiAuthToken();
options.headers = {'Authorization': `Bearer ${token}`}
return {
mustRetry: true,
options: options,
}
}
request({
url: 'https://api.domain.com/v1/a/b'
json:true,
retryStrategy: myRetryStrategy
}, function(err, response, body){
});
How to define your own delay strategy
A delay strategy let you specify how long request-retry should wait before trying again the request
function myDelayStrategy(err, response, body){
return Math.floor(Math.random() * (3500 - 500 + 1) + 500);
}
request({
url: 'https://api.domain.com/v1/a/b'
json:true,
delayStrategy: myDelayStrategy
}, function(err, response, body){
});
Here is how to implement an exponential backoff strategy:
function getExponentialBackoff(attempts) {
return (Math.pow(2, attempts) * 100) + Math.floor(Math.random() * 50);
}
function constructExponentialBackoffStrategy() {
let attempts = 0;
return () => {
attempts += 1;
return getExponentialBackoff(attempts);
};
}
request({
url: 'https://api.domain.com/v1/a/b'
json:true,
delayStrategy: constructExponentialBackoffStrategy()
}, function(err, response, body){
});
How to access the underlying request library
You can access to the underlying request
library thanks to request.Request
:
const request = require('requestretry');
console.log(request.Request);
Thus, if needed, it's possible to monkey-patch or extend the underlying Request library:
request.Request = class extends request.Request {
constructor(url, options, f, retryConfig) {
super(url, options, f, retryConfig);
console.log('Request', url, options, f, retryConfig);
}
}
Modifying request
options
You can use the defaults
method to provide default options like so:
var request = require('requestretry').defaults({ json: true, retryStrategy: myRetryStrategy });
API surface
As with request
, several helpers are provided for various HTTP methods and usage:
request(options [, callback])
.request(url [, callback])
- same as request(options [, callback])
.request(url, options [, callback])
- same as request(options [, callback])
.request.get(url [, callback])
- same as request(options [, callback])
, defaults options.method
to GET
.request.get(url, options [, callback])
- same as request(options [, callback])
, defaults options.method
to GET
.request.head(url)
- same as request(options [, callback])
, defaults options.method
to HEAD
.request.post(url)
- same as request(options [, callback])
, defaults options.method
to POST
.request.put(url)
- same as request(options [, callback])
, defaults options.method
to PUT
.request.patch(url)
- same as request(options [, callback])
, defaults options.method
to PATCH
.request.del(url)
- same as request(options [, callback])
, defaults options.method
to DELETE
.request.delete(url)
- same as request(options [, callback])
, defaults options.method
to DELETE
.
You want to support my work?
I maintain this project in my free time, if it helped you, well, I would be grateful to buy a beer thanks to your paypal or Bitcoins, donation!
Francois-Guillaume Ribreau (npm@fgribreau.com)