【问题标题】:nodejs retry function if failed X times如果失败X次,nodejs重试功能
【发布时间】:2019-07-28 15:08:06
【问题描述】:

我希望我的函数执行 X(=3) 次直到成功。

在我的情况下,我正在运行 kinesis.putRecord(来自 AWS API),如果它失败 - 我想再次运行它直到它成功,但不超过 3 次尝试。

我是 NodeJS 的新手,我写的代码很糟糕。

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)

我保证错误的结果。之后,如果 err 为空,则一切正常。否则,继续运行相同的命令。

我确信有一种更聪明的方法可以做到这一点。任何帮助将不胜感激。

【问题讨论】:

    标签: node.js amazon-web-services promise callback async-await


    【解决方案1】:

    制作一个小模块,比如try-and-try-again.js:

    exports = module.exports = tryAndTryAgain;
    
    function tryAndTryAgain( 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;
    }
    

    然后你可以在任何地方使用它:

    const tryAndTryAgain = require('./try-and-try-again');
    
    function somethingThatMightNeedARetry() { ... }
    
    const succeeded = tryAndTryAgain( 3 , null, somethingThatMightNeedARetry, 'arg-1', 'arg-2', 'arg-3' );
    

    【讨论】:

      【解决方案2】:

      我认为,所有的 Aws 函数都可以开箱即用地返回 Promise,然后您可以将调用放入 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 ++;
      }
      

      【讨论】:

      • 它抛出SyntaxError: await is only valid in async function
      • @TheCrystalShip,在您的问题中,您在async 函数中有代码,因此假设您将此答案代码放在async 函数中。
      • 将我的 sn-p 放入您的 waterfall 函数中。已经是async
      • 另一个改进是使用经典的for 循环,而不是while
      • @trincot 就我们只想执行代码直到它成功为止,我发现 while 在这里更好,因为 forbreak 可能会令人困惑......
      【解决方案3】:

      功能风格:

      ...
      await tryUntilSucceed(() => kinesis.putRecord(params).promise());
      ...
      
      async function tryUntilSucceed(promiseFn, maxTries=3) {
          try {
              return await promiseFn();
          } catch (e) {
              if (maxTries > 0) {
                  return tryUntilSucceed(promiseFn, maxTries - 1);
              }
              throw e;
          }
      }
      

      【讨论】:

        【解决方案4】:

        有一个名为async-retrynpm 包非常方便。它充当您的函数的包装器,并在发生任何异常时重试(您可以处理一些异常,请参见下面的示例)。

        // Packages
        const retry = require('async-retry')
        const fetch = require('node-fetch')
         
        await retry(async bail => {
          // if anything throws, we retry
          const res = await fetch('https://google.com')
         
          if (403 === res.status) {
            // don't retry upon 403
            bail(new Error('Unauthorized'))
            return
          }
         
          const data = await res.text()
          return data.substr(0, 500)
        }, {
          retries: 5
        })
        

        【讨论】:

          猜你喜欢
          • 2019-11-17
          • 2018-06-29
          • 2020-08-14
          • 1970-01-01
          • 1970-01-01
          • 2016-03-05
          • 2015-09-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多