Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Failed to load latest commit information.
test Merge pull request #2 from deviousdodo/initialize-range
.gitignore Generated gem stub.
.travis.yml Make travis use default rake task. Add changelog.
LICENSE Generated gem stub. Update docs to include #initialize with array and range.
exponential-backoff.gemspec Add rake to test dependencies.

Exponential Backoff

Build Status

Too lazy to make retries to external services in a fashion that providers recommend? Never heard of exponential backoff technique? Now there is no excuse not to be nice.


Add this line to your application's Gemfile:

gem 'exponential-backoff'

And then execute:

$ bundle

Or install it yourself as:

$ gem install exponential-backoff


Start with specifying minimal and maximal intervals, that is 4s and 60s respectively:

minimal_interval = 4.0
maximal_elapsed_time = 60.0

backoff =, maximal_elapsed_time)

Arrays and ranges work for your convenience too:

backoff =
backoff =[minimal_interval, maximal_elapsed_time])

You can get intervals for specified range:

backoff.intervals_for(0..5) # [4.0, 8.0, 16.0, 32.0, 60.0, 60.0]

Enumerate on them:

backoff.intervals.each do |interval|

Or just get interval for requested, that is 3rd, iteration:

backoff.interval_at(3) # 32.0

Intervals don't exceed maximal allowed time:

backoff.interval_at(20) # 60.0

Backoff instance maintains state, you can ask for next interval...

backoff.next_interval # 4.0
backoff.next_interval # 8.0

...and reset it to start from beginning

backoff.next_interval # 4.0

Finally you can specify interval multiplier and randomization factor:

backoff =, max_elapsed)
backoff.multiplier = 1.5
backoff.randomize_factor = 0.25

backoff.intervals_for(0..2) # [3.764, 6.587, 9.76]

You can peek what is the current interval:

backoff.current_interval # 3.764

You can check if given iteration is one of intervals or maximum interval multiple:

backoff =, 10)
backoff.iteration_active?(4) # true
backoff.iteration_active?(20) # true
backoff.iteration_active?(3) # false

There is also sugar for executing block of code until successful with increasing intervals:

backoff.until_success do |interval, retry_count|
  # do your thing
  # when last line in block evaluates to true, elapsed time clear and loop breaks
  # when false, increase interval and retry

  # you can break loop earlier if you want,
  # `nil` return value is considered a success
  return if retry_count > 3

Running tests

bundle exec rake test

Supported rubies

Targets all Rubies (including Rubinius and JRuby) provided it's at least 1.9 mode.

Something went wrong with that request. Please try again.