I\'m using the Bluebird promise library. I have a chain of promisified functions like the following:
receiveMessageAsync(params)
.then(function(data)
Here's a sample retry function (not yet tested):
function retry(maxRetries, fn) {
return fn().catch(function(err) {
if (maxRetries <= 0) {
throw err;
}
return retry(maxRetries - 1, fn);
});
}
The idea is that you can wrap a function that returns a promise with something that will catch and retry on error until running out of retries. So if you're going to retry sendResponseAsync
:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
return retry(3, function () { return sendResponseAsync(response); });
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// handle error here
});
Since the retry
promise won't actually throw until all retries have been exhausted, your call chain can continue.
Edit:
Of course, you could always loop forever if you preferred:
function retryForever(fn) {
return fn().catch(function(err) {
return retryForever(fn);
});
}
I just released https://github.com/zyklus/promise-repeat, which retries a promise until it either times out or a maximum number of attempts are hit. It allows you to write:
receiveMessageAsync(params)
...
.spread(retry(
function(response, data) {
return sendResponseAsync(response);
}
))
...
Here is a small helper that acts like then
but retries the function.
Promise.prototype.retry = function retry(onFulfilled, onRejected, n){
n = n || 3; // default to 3 retries
return this.then(function(result) {
return Promise.try(function(){
return onFulfilled(result); // guard against synchronous errors too
}).catch(function(err){
if(n <= 0) throw err;
return this.retry(onFulfilled, onRejected, n - 1);
}.bind(this)); // keep `this` value
}.bind(this), onRejected);
};
Which would let you write your code prettier like:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.retry(function(response, data) {
return sendResponseAsync(response); // will retry this 3 times
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// I don't like catch alls :/ Consider using `.error` instead.
});