【问题标题】:Retry async/await try and catch block three times before responding with an error在响应错误之前重试 async/await try and catch 块 3 次
【发布时间】:2019-08-08 23:30:02
【问题描述】:

发现了类似的问题,但没有一个回答我的问题。在抛出错误之前,我需要尝试运行异步函数 3 次。目前正在使用 while 循环执行此操作,开始时感觉不对。这一切都发生在快速路线上。这是我的代码目前的样子:

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  let tries = 0
  while (true) {
    try {
      await myAsyncFunction(body)
      res.json({ success: true, message: 'Done!' })
    } catch (err) {
      if (tries >= MAX_NUMBER_OF_TRIES) {
        res.json({ success: false, message: err && err.message })
      }
    }
    tries++
  }
}

其中一个问题是,当我这样做时,我总是收到以下错误:

UnhandledPromiseRejectionWarning: 错误 [ERR_HTTP_HEADERS_SENT]: 发送到客户端后无法设置标头

如果没有循环,这不会出现。 所以我想问题是,如何在响应错误之前将这些调用限制为三次尝试?这是正确的路径还是有其他方法可以做到?为什么我会遇到标题问题?

【问题讨论】:

  • 循环什么时候结束?提示:从不。
  • learnrxjs.io/operators/error_handling/retry.html 可能是rxjs retry 运营商会为你做的
  • 要处理错误,您必须在异步函数旁边调用catch 函数 --> myAsyncFunction(body).catch(x => {});
  • 错误是关于设置headers,但你的代码与错误无关。
  • @Sergej Not necessary to catch it like that,因为 myAsyncFunction 已经在等待。此外,res.json 设置内容 标头,这就是如果它被调用两次会导致错误的原因。

标签: javascript node.js express async-await


【解决方案1】:

是的,while 循环看起来很粗略。你永远不会停止它。只需使用普通循环即可。当你得到回应时,你也需要休息。

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  var message;
  for (let tries = 0; tries < MAX_NUMBER_OF_TRIES; tries++) {
    try {
      await myAsyncFunction(body)
      res.json({ success: true, message: 'Done!' })
      return
//    ^^^^^^
    } catch (err) {
      message = err && err.message;
      console.log(`Try ${tries}: ${err}`)
    }
  }
  res.json({ success: false, message })
}

这个奇怪的小控制流的替代方法是使用递归,它非常适合重试:

async function getResult(body, retries) {
  try {
    await myAsyncFunction(body)
    return {success: true, message: 'Done'}
  } catch(err) {
    if (retries > 0)
      return getResult(body, retries-1)
    else
      return {success: false, message: err && err.message}
  }
}

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  const RETRIES = MAX_NUMBER_OF_TRIES - 1
  res.json(await getResult(body, RETRIES))
})

【讨论】:

    【解决方案2】:

    你应该像这样在res.json({ success: false, message: err &amp;&amp; err.message }) 之后返回:

    ...
    res.json({ success: false, message: err && err.message })
    return
    ...
    
    

    【讨论】:

      【解决方案3】:

      将重试逻辑移至异步函数,如下所示 这只是一个如何实现的示例,请根据您的需要进行调整。

      router.post('/', async function(req, res) {
        try {
          var result = await asyncFunc(3 /* retries */);
          res.send(result);
        } catch(ex)
        {
          res.send(ex);
        }
      })
      

      在你的异步函数中,你可以实现类似

      async asyncFunc(retries)
      {
        for(var i = 0; i < retries; i++)
        {
          var result = await doSomething();
          if(result)
          {
            // break the loop
            return result;
          }
        }
      
         // if we land here, so the number of retries was exceeded
         throw Error("...");
      }
      

      【讨论】:

        【解决方案4】:

        async-retry 包将为您完成此操作;代码的数量实际上是相似的,但它有更多的能力,而且不那么繁琐。

        例如:

        const retry = require('async-retry')
        
        try {
          await retry(async () => {
            await myAsyncFunction(body)
            res.json({ success: true, message: 'Done!' })
          }, {
            retries: 3,
          }) 
        } catch (err) => 
        {
           res.json({ success: false, message: err && err.message })
        }
        

        外部 catch 处理重试 3 次并转义 retry 块的情况。您还可以设置一个onError 函数,该函数具有为每个错误(例如日志记录)执行的逻辑。

        【讨论】:

          猜你喜欢
          • 2021-11-16
          • 2018-06-21
          • 2018-10-02
          • 2021-08-28
          • 2019-03-14
          • 1970-01-01
          • 2019-09-15
          • 2020-09-07
          • 1970-01-01
          相关资源
          最近更新 更多