Retry the async function if the error persists
How can I change my logic to retry if err.retryable = true in the following code:
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) {
//...
})
You can give the call a queue name and re-include it in the retry request. Try the following:
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) {
//...
});
source to share
In addition to dfsq's advice to name your callback and use it asynchronously in a recursive manner, see also async.retry from async by Caolan McMahon. Example:
async.retry(3, apiMethod, function(err, result) {
// do something with the result
});
More complex example:
async.auto(
{
users: api.getUsers.bind(api),
payments: async.retry(3, api.getPayments.bind(api))
}, function(err, results) {
// do something with the results
}
);
More details in the docs .
UPDATE
Best solution for your use case:
I wrote a utility function that you can use to make your original method support any number of attempts (with support err.retryable
).
You can use it like this:
var retryingFunction = withRetries(sqs, sqs.getQueueUrl);
(Please note that you need to provide both sqs
and sqs.getQueueUrl
)
And now you can use retryingFunction
it just as you would sqs.getQueueUrl
, but with a number of tries as the first arguments. Repetitions are performed only when err.retryable
true.
So instead of:
sqs.getQueueUrl({'QueueName': queue.queue}, function (err, qurl) {
// ...
});
you can use:
retryingFunction(3, {'QueueName': queue.queue}, function (err, qurl) {
// ...
});
where 3 is the number of attempts.
And this is the function I wrote to do my best:
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;
}
Watch this LIVE DEMO to play with it and see how it works.
It works great in the demo, I hope it works for your code as well.
source to share