如果错误可重试,请重试异步功能

时间:2014-12-22 20:58:37

标签: javascript node.js asynchronous callback

如果以下代码中的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) {
    //...
})

2 个答案:

答案 0 :(得分:3)

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

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

更多详情in the docs

更新

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

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

你可以这样使用它:

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

(请注意,您需要提供 sqs sqs.getQueueUrl

现在您可以像使用retryingFunction一样使用sqs.getQueueUrl,但可以使用多次重试作为第一个参数。只有在err.retryable为真时才会重试。

现在,而不是:

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

请参阅此LIVE DEMO进行播放,了解其工作原理。

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

答案 1 :(得分:1)

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

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) {
    //...
});