Exponential Backoff
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.
Installation
Add this line to your application's Gemfile:
gem 'exponential-backoff'
And then execute:
$ bundle
Or install it yourself as:
$ gem install exponential-backoff
Usage
Start with specifying minimal and maximal intervals, that is 4s
and 60s
respectively:
minimal_interval = 4.0
maximal_elapsed_time = 60.0
backoff = ExponentialBackoff.new(minimal_interval, maximal_elapsed_time)
Arrays and ranges work for your convenience too:
backoff = ExponentialBackoff.new(minimal_interval..maximal_elapsed_time)
backoff = ExponentialBackoff.new([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|
sleep(interval)
end
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.clear
backoff.next_interval # 4.0
Finally you can specify interval multiplier and randomization factor:
backoff = ExponentialBackoff.new(min_interval, 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 = ExponentialBackoff.new(1, 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
end
Running tests
bundle exec rake test