Flexible, fault-tolerant operations for Typescript.
Switch branches/tags
Nothing to show
Clone or download
Pull request Compare This branch is even with TobyColeman:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



styled with prettier Coverage Status CircleCI

Flexible, fault-tolerant operations for Typescript.


  • Node >=4.6.0
  • Typescript >=2.0
  • Experimental decorators
  • ES6 target (for async/await support)


npm install node-endeavour --save

Example Usage

import endeavour from 'node-endeavour'

function unreliable () {
  if (Math.random <= 0.25) return Promise.resolve()
  return Promise.reject()

// create a fault tolerant operation. This will be retried
// 10 times, backing off exponentially with no maximum delay.
const faultTolerant = endeavour(unreliable)

async function main () {
  let result

  try {
    result = await faultTolerant()
  } catch (error) {



endeavour(thenableFunction, [options], [ctx])

Creates a new EndeavourRunnable; a wrapped version of your function that will retry indefinitely, or up until some specified limit. The default options are as follows:

  • retries The maximum amount of times to retry the operation. Defaults to 10.
  • constant The base in exponential backoff, or the slope in linear backoff. Defaults to 2.
  • minTimeout The number of milliseconds before starting the first retry. Default is 1000.
  • maxTimeout The maximum number of milliseconds between two retries. Default is Infinity.

You may also specify this (useful for wrapping instance methods).

class Thing {
  doSomethingUnreliable () {}

const instance = new Thing()

const faultTolerant = endeavour(instance.doSomethingUnreliable, instance)

  .then(res => { console.log('yay!') })
  .catch(e => { console.log(':(')) })

See the decorators section for a more terse way of handling these cases.

EndeavourRunnable([arguments], [intercept])

Using your wrapped function from endeavour(...) works much in the same way as before. Arguments are be passed like this:

myFaultTolerantOperation(['some', 'arguments'])

The wrapped operation also accepts and optional function to allow for greater control over how retries should proceed.

faultTolerantOperation((result, next) => {
  if (result.error instanceof MyCustomError) {
    return next(new Error('something went horribly wrong :('))

Calling next() with an error will stop your operation. You can also pass in an new array of arguments for subsequent retries.

faultTolerantOperation((result, next) => {
  if (result.error instanceof MyCustomError) {
    return next(['new', 'args'])

You could also just inspect the result of the last attempt.

faultTolerantOperation(result => {



A decorator for providing metadata about how retriable methods in a class should operate. Takes the options defined here.


Provides the same functionality as endeavour, but for class methods.

@endeavourable({ retries: 15 })
class {
  // retried 15 times
  unreliableMethod () {
    if (Math.random <= 0.25) return Promise.resolve()
    return Promise.reject()

  // retried 5 times
  @endeavourify({ retries: 5 })
  doSomething () { }

  // retried 10 times
  otherThing() { }

When no arguments are given to @endeavourable or @endeavourify, the defaults provided here will be used.

Want something for plain old JS? Check out node-retry.