如果错误可重试,请重试异步函数

Retry an async function if the error is retryable

本文关键字:重试 异步 函数 如果 错误      更新时间:2023-09-26

如果以下代码中的err.retryable = true,我如何更改我的逻辑以重试:

async.each(queues, function (queue, callback) {
    sqs.getQueueUrl({'QueueName': queue.queue}, function (err, qurl) {
        if (err) {
            if (err.retryable) {
                // How to retry  sqs.getQueueUrl({'QueueName': queue.queue}...?
            } else {
                console.error(err, err.stack);
                callback(err);
            }
        }else{
            //Do lots of things here
        }        
    })
}, function (err) {
    //...
})

除了 dfsq 建议命名回调并以异步递归方式使用它之外,另请参阅 Caolan McMahon 的 async 模块中的 async.retry。例:

async.retry(3, apiMethod, function(err, result) {
    // do something with the result
});

更复杂的示例:

async.auto(
  {
    users: api.getUsers.bind(api),
    payments: async.retry(3, api.getPayments.bind(api))
  }, function(err, results) {
    // do something with the results
  }
);

文档中的更多详细信息。

更新

为您的用例提供更好的解决方案:

我编写了一个实用程序函数,您可以使用它使您的原始方法支持任意数量的重试(err.retryable支持(。

您可以通过以下方式使用它:

var retryingFunction = withRetries(sqs, sqs.getQueueUrl);

(请注意,您需要同时提供sqssqs.getQueueUrl(

现在,您可以像使用 sqs.getQueueUrl 一样使用 retryingFunction,但需要多次重试作为第一个参数。仅当err.retryable为 true 时,才会进行重试。

所以现在,而不是:

sqs.getQueueUrl({'QueueName': queue.queue}, function (err, qurl) {
  // ...
});

您可以使用:

retryingFunction(3, {'QueueName': queue.queue}, function (err, qurl) {
  // ...
});

其中 3 是重试次数。

这是我为使上述功能成为可能而编写的函数:

function withRetries(obj, method) {
  if (!method) {
    method = obj;
    obj = null;
  }
  if (typeof method != "function") {
    throw "Bad arguments to function withRetries";
  }
  var retFunc = function() {
    var args = Array.prototype.slice.call(arguments);
    var retries = args.shift();
    var callback = args.pop();
    if (typeof retries != "number" || typeof callback != "function") {
      throw "Bad arguments to function returned by withRetries";
    }
    var retryCallback = function (err, result) {
      if (err && err.retryable && retries > 0) {
        retries--;
        method.apply(obj, args);
      } else {
        callback(err, result);
      }
    };
    args.push(retryCallback);
    method.apply(obj, args);
  };
  return retFunc;
}

观看此现场演示以使用它,看看它是如何工作的。

它在演示中运行良好,我希望它也适用于您的代码。

您可以为队列回调指定一个名称,并在重试请求中再次提供该名称。试试这个:

async.each(queues, function (queue, callback) {
    sqs.getQueueUrl({'QueueName': queue.queue}, function queueCallback(err, qurl) {
        if (err) {
            if (err.retryable) {
                sqs.getQueueUrl({'QueueName': queue.queue}, queueCallback);
            } else {
                console.error(err, err.stack);
                callback(err);
            }
        } else {
            //Do lots of things here
        }
    });
}, function (err) {
    //...
});