nodejs retry function if failed X times

2019-07-31 17:48发布

问题:

I want my function to execute X(=3) times until success.

In my situation I'm running kinesis.putRecord (from AWS API), and if it fails - I want to run it again until it succeeds, but not more than 3 tries.

I'm new to NodeJS, and the code I wrote smells bad.

const putRecordsPromise = function(params){
    return new Promise((resolve, reject) => {
        kinesis.putRecord(params, function (err, data) {
            resolve(err)
        });
    })
}

async function waterfall(params){
    try{
        let triesCounter = 0;
        while(triesCounter < 2){
            console.log(`try #${triesCounter}`)
            let recordsAnswer = await putRecordsPromise(params)
            if(!recordsAnswer){
                console.log("success")
                break;
            }
            triesCounter += 1;
        }
        // continue ...

    } catch(err){
        console.error(err)
    }
}

waterfall(params)

I promise the err result. Afterwards, If the err is empty, then all good. otherwise, continue running the same command.

I'm sure there is a smarter way to do this. Any help would be appreciated.

回答1:

I think, all the Aws functions can return a Promise out of the box, then you can just put the call into try/catch:

let triesCounter = 0;
while(triesCounter < 2){
    console.log(`try #${triesCounter}`)
    try {
        await kinesis.putRecord(params).promise();
        break;  // 'return' would work here as well
    } catch (err) {
       console.log(err);
    }
    triesCounter ++;
}


回答2:

Make a little module, say try-and-try-again.js:

exports = module.exports = tryAndTryAgain;

function tryUntilSuccess( maxTries, thisContext , fn, ...argv) {
  let success = false;

  for (let i = i ; i < maxTries && !success ; ++i ) {
    let rc = fn.apply(thisContext, args);
    success = rc == 0 ? true : false;
  }

  return success;
}

Then you can use it anywhere:

const tryAndTryAgain = require('./try-and-try-again');

function somethingThatMightNeedARetry() { ... }

const succeeded = tryAndTryAgain( 3 , null, somethingThatMightNeedARetry, 'arg-1', 'arg-2', 'arg-3' );


回答3:

In functional style:

...
await tryUntilSucces(() => kinesis.putRecord(params).promise());
...

async function tryUntilSucces(promiseFn, maxTries=3) {
    try {
        return await promiseFn();
    } catch (e) {
        if (maxTries > 0) {
            return tryUntilSucces(promiseFn, maxTries - 1);
        }
        throw e;
    }
}