Nodejs HTTP retry при тайм-ауте или ошибке
Я пытаюсь автоматически повторять HTTP-запросы по таймауту или ошибке.
В настоящее время мой код выглядит следующим образом:
var req = http.get(url, doStuff)
.on('error', retry)
.setTimeout(10000, retry);
Однако один запрос может иногда запускать как события "при ошибке", так и "таймаут". Что является лучшим способом реализации повторных попыток?
Ответы
Ответ 1
Я искал то же самое и нашел интересный модуль requestretry, хорошо подходящий для такого требования.
Вот использование:
var request = require('requestretry')
request({
url: myURL,
json: true,
maxAttempts: 5, // (default) try 5 times
retryDelay: 5000, // (default) wait for 5s before trying again
retrySrategy: request.RetryStrategies.HTTPOrNetworkError // (default) retry on 5xx or network errors
}, function(err, response, body){
// this callback will only be called when the request succeeded or after maxAttempts or on error
if (response) {
console.log('The number of request attempts: ' + response.attempts);
}
})
Ответ 2
Вы можете попробовать что-то вроде этого:
function doRequest(url, callback) {
var timer,
req,
sawResponse = false;
req = http.get(url, callback)
.on('error', function(err) {
clearTimeout(timer);
req.abort();
// prevent multiple execution of `callback` if error after
// response
if (!sawResponse)
doRequest(url, callback);
}).on('socket', function(sock) {
timer = setTimeout(function() {
req.abort();
doRequest(url, callback);
}, 10000);
}).once('response', function(res) {
sawResponse = true;
clearTimeout(timer);
});
}
UPDATE: В последних/современных версиях node теперь вы можете указать опцию timeout
(измеренную в миллисекундах), которая устанавливает тайм-аут сокета (до подключения сокета). Например:
http.get({
host: 'example.org',
path: '/foo',
timeout: 5000
}, (res) => {
// ...
});
Ответ 3
Это был код, который работал у меня. Ключ должен был уничтожить сокет после таймаута, а также проверить, что ответ завершен.
function httpGet(url, callback) {
var retry = function(e) {
console.log("Got error: " + e.message);
httpGet(url, callback); //retry
}
var req = http.get(url, function(res) {
var body = new Buffer(0);
res.on('data', function (chunk) {
body = Buffer.concat([body, chunk]);
});
res.on('end', function () {
if(this.complete) callback(body);
else retry({message: "Incomplete response"});
});
}).on('error', retry)
.setTimeout(20000, function(thing){
this.socket.destroy();
});
}
Ответ 4
Используя Request-обещание, почему бы просто не использовать цикл while внутри асинхронной анонимной функции:
(async () => {
var download_success = false;
while (!download_success) {
await requestpromise(options)
.then(function (response) {
download_success = true;
console.log('Download SUCCESS');
})
.catch(function (err) {
console.log('Error downloading : ${err.message}');
});
}
})();
Также обратите внимание, что модуль requestretry существует.