Posted by Edd Mann on Apr 21, 2017

Handling Retries and Back-off Attempts with JavaScript Promises

Promises are an invaluable abstraction around ‘eventual’ results within asynchronous operations. I recently had the need to be able to retry a Promise-based action in the event of a failure. It turned out to be very easy to implement such a process using simple recursive constructs.

Initially I only required the ability to retry a desired amount of times, before eventually failing if still unsuccessful. You can see how easy it was to describe this problem in Promise-form within the function below.

const retry = (retries, fn) =>
  fn().catch(err => retries > 1 ? retry(retries - 1, fn) : Promise.reject(err));

However, what I eventually required was the ability to ‘back-off’ and provide an increasing grace-period between the operation attempts. Again, it was very easy to describe this within a Promise as shown below.

const pause = (duration) => new Promise(res => setTimeout(res, duration));

const backoff = (retries, fn, delay = 500) =>
  fn().catch(err => retries > 1
    ? pause(delay).then(() => backoff(retries - 1, fn, delay * 2))
    : Promise.reject(err));

As you can see, both implementations use a recursive structure with decrementing retries to hit the base-case. What I find so impressive with the Promise abstraction is how easy it is to codify complex problems such as this with minimal code.

Demo

Below you can see a JSBin demo which uses an intentionally unreliable Promise to exercise the two functions retrying behaviour.

JS Bin on jsbin.com

Jobs at MyBuilder

We need an experienced software engineer who loves their craft and wants to share their hard-earned knowledge.

View vacancies
comments powered by Disqus