/retry-js

Javascript library to make it easy when dealing with retrying asynchronous code that could fail.

Primary LanguageJavaScriptMIT LicenseMIT

Retry Build status

Retry.js for when things don't go to plan. This is a library that aims to make it easy to create asychronous retry logic.

Usage

In order to avoid any namespace conflicts Retry uses the public namespace com.jivatechnology (reverse DNS scheme). You can import this into your local scope with something like:

var Retry = com.jivatechnology.Retry;

Configuring

We can configure what we need from the constructor:

var retry = new Retry({
  timeout:   3000,                     // specified in ms, how long to wait for a success
  interval:  1000,                     // How long to wait between failures before retrying initially
  max_tries: 4,                        // How many times to attempt retrying before failing
  fallback:  Retry.Fallbacks.Constant, // The scheme to use for calculating the wait between retries

  func:      function(){},             // The function to retry

  onSuccess: function(){ console.info("Yay") },
  onFailure: function(){ console.warn("Nay") },
})

It's possible to customise it once the object has been instantiated:

var retry = new Retry({timeout: 400});
retry.timeout();
=> 400
retry.timeout(500);
=> 500

Executing

To start attempting the function we need to execute run:

retry.run();

The function to retry will be checked to make sure it doesn't

  • Timeout
  • Throw an error
  • Fail (it must call retry.failure() if it does)

If the function has succeeded it must call retry.success().

For example:

var retry = new Retry();
retry.func( function(){
  if(Math.random() > 0.5){
    retry.success();
  } else {
    retry.failure();
  }
});
retry.onSuccess.add(function(){
  console.info("Done!");
});

retry.run() // Start attempting to run func

This is useful for situations where you have non blocking code that uses callback when a result is returned (e.g. a jQuery AJAX request).

Callbacks

We can add as many callbacks as we need for success or failure as well (see callback-js):

retry.onSuccess.add(function(){ console.info("Me too")});
retry.onSuccess.add(function(){ console.info("and me!")});

Fallback

The fallback specifies how the interval changes over time. Often it's useful to get behaviour whereby we intially retry quickly, then ease off. We can use the fallback function to describe this logic.

For example if we wanted a fallback mechanism that increases the wait by interval for each attempt we could write:

var retry = new Retry();
retry.fallback(function(){
  return this.attempt() * this.interval();
});

There are also some standard fallback functions to get started with.

- `Retry.Fallbacks.Constant`, will always return the same interval.
- `Retry.Fallbacks.Fibonacci`, will increase the interval in a similar way to a fibonacci sequence

Stopping

Once you have finished using the retry object you can stop it. This will prevent any callbacks being called, ignore any requests to failure or success. You can then reenable it by calling run.

var retry = new Retry();
retry.func(function(){ ... })
retry.run();

... Do work ...

retry.stop();

Tests

All of the tests are written in Jasmine. Sprockets is used to describe dependencies between the files. To run the tests, you will first need to install Ruby and Bundler. Once you have this:

$ bundle install
$ bundle exec rake jasmine

Open your browser to http://localhost:8888

If you want to run the tests directly in the console just type:

$ bundle exec rake jasmine:ci
/Users/theo/.rvm/rubies/ruby-1.9.3-p0/bin/ruby -S rspec spec/javascripts/support/jasmine_runner.rb --colour --format progress
[2012-03-15 15:46:50] INFO  WEBrick 1.3.1
[2012-03-15 15:46:50] INFO  ruby 1.9.3 (2011-10-30) [x86_64-darwin11.1.0]
[2012-03-15 15:46:50] INFO  WEBrick::HTTPServer#start: pid=39919 port=63714
Waiting for jasmine server on 63714...
jasmine server started.
Waiting for suite to finish in browser ...
..........................................

Or you can check the current status of master using Travis

Building

Provided you have all of the software installed to run the tests (see above). You can build the code using:

$ bundle exec rake build

This will create a copy of the code in the build folder. It will also package up any external dependencies (such as callback-js). If you are already using Sprockets then it is best to copy the src folder to your project and let that deal with the build dependencies (avoids duplication).

Future

  • Flap detection
  • More fallback functions