Reputation: 15
I'm developing a script for personal needs. I need to retry if an error returned, but I don't know how to fix it. how to resolve it?
const request = require("request");
const co = require('co');
function init() {
co(function *(){
var res = yield GetData();
console.log(res);
});
}
function onerror(error) {
console.log("error below");
console.log(error);
console.log(error.code);
console.error(error.stack);
}
function send_request(options, callback){
co(function *(){
let RetryAttemptCount = 0;
let MaxRetries = 3;
let res;
res = yield request(options, function (error, response, body) {
var tmp;
if (!body && error && !response) {
RetryAttemptCount++;
console.log('increase RetryAttemptCount :',RetryAttemptCount);
throw new onerror(error);
} else if (!error) {
tmp = JSON.parse(body);
return tmp;
}
});
}).catch(onerror);
}
function GetData() {
return new Promise(function(resolve, reject){
var options = { method: 'GET', url: 'https://api.upbit.com/v1/market/all' };
send_request(options, (res) => {
resolve(res);
});
});
}
init();
But I get the following error:
TypeError: You may only yield a function, promise, generator, array, or object, but the following object was passed: "[object Object]"
Upvotes: 1
Views: 2260
Reputation: 276306
You can do it very generally with a simple retry function:
function retry(fn, attempts = 3, delay = 2000) {
return async function(...args) {
for(let i = 0; i < attempts; i++) {
try {
await fn.call(this, ...args); // delegate
} catch (e) {
if(attempts > 0) await new Promise(r => setTimeout(r, delay));
else throw e;
}
}
}
}
This would let you do:
let retried = retry(fn);
// ... then later
await retried({ ... params });
Upvotes: 2
Reputation: 111
Thanks to @Benjamin's answer I came up with this modified code which is a bit simplified plus adds exponential backoff stuff.
function retry(fn, retries = 5, interval = 2000, backOff = 2) {
return async function(...args) {
let delay = interval;
do {
try {
console.log('Trying...');
return await fn(...args);
} catch (e) {
console.error(e['message']);
retries--;
if (retries > 0) {
console.log('Waiting ' + delay + 'ms...');
await new Promise(resolve => setTimeout(resolve, delay));
delay *= backOff;
} else {
throw e;
}
}
} while (true);
}
}
let x = 0;
function mightFail(value) {
x++;
if (x < 5) {
throw new Error('transient error occurred');
}
return value;
}
async function test() {
try {
const result = await retry(mightFail)(12345);
console.log('Success: ' + result);
} catch (e) {
console.error('Failure: ' + e);
}
}
test();
Upvotes: 1
Reputation: 1976
I suggest you use requestretry
npm instead of request. It's simple to use
var request = require('requestretry');
request({
url: 'https://api.domain.com/v1/a/b',
json: true,
// The below parameters are specific to request-retry
maxAttempts: 5, // (default) try 5 times
retryDelay: 5000, // (default) wait for 5s before trying again
retryStrategy: 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);
}
});
You can control retry count with changing maxAttempts value
Upvotes: 0