How can I change my logic to retry if the 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) {
//...
})
How can I change my logic to retry if the 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) {
//...
})
Share
Improve this question
asked Dec 22, 2014 at 20:58
user3421904user3421904
2 Answers
Reset to default 3In addition to the advice by dfsq to name your callback and use it an asynchronously recursive manner, see also async.retry from the async module by Caolan McMahon. Example:
async.retry(3, apiMethod, function(err, result) {
// do something with the result
});
More plex 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
A better solution for your use case:
I wrote a utility function that you can use to make your original method support any number of retries (with err.retryable
support).
You can use it this way:
var retryingFunction = withRetries(sqs, sqs.getQueueUrl);
(Note that you need to provide both sqs
and sqs.getQueueUrl
)
And now you can use the retryingFunction
just like you would use sqs.getQueueUrl
but with a number of retries as the first arguments. The retries will only be done when err.retryable
is true.
So now, 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 retries.
And this is the function that I wrote to make the above possible:
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;
}
See this LIVE DEMO to play with it and see how it works.
It works fine in the demo, I hope it will also work for your code.
You can give queue callback a name and provide it in retry request again. Try this:
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) {
//...
});