Search code examples
javascriptnode.jspromisegenerator

How can I retry function?


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]"


Solution

  • 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 });