by ooyala

ooyala / retries

A tiny Rubygem for retrying code with randomized, exponential backoff.

203 Stars 11 Forks Last release: Not found MIT License 18 Commits 5 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:


Retries is a gem that provides a single function,

, to evaluate a block with randomized, truncated, exponential backoff.

There are similar projects out there (see retry_block and retry_this, for example) but these will require you to implement the backoff scheme yourself. If you don't need randomized exponential backoff, you should check out those gems.


You can get the gem with

gem install retries
or simply add
gem "retries"
to your Gemfile if you're using bundler.


Suppose we have some task we are trying to perform:

. This might be a call to a third-party API or a flaky service. Here's how you can try it three times before failing:
require "retries"
with_retries(:max_tries => 3) { do_the_thing }

The block is passed a single parameter,

, which is the number of attempts that have been made (starting at 1):
with_retries(:max_tries => 3) do |attempt_number|
  puts "Trying to do the thing: attempt #{attempt_number}"

Custom exceptions

By default

rescues instances of
. You'll likely want to make this more specific to your use case. You may provide an exception class or an array of classes:
with_retries(:max_tries => 3, :rescue => RestClient::Exception) { do_the_thing }
with_retries(:max_tries => 3, :rescue => [RestClient::Unauthorized, RestClient::RequestFailed]) do


allows you to pass a custom handler that will be called each time before the block is retried. The handler will be called with three arguments:
(the rescued exception),
(the number of attempts that have been made thus far), and
(the number of seconds since the start of the time the block was first attempted, including all retries).
handler = do |exception, attempt_number, total_delay|
  puts "Handler saw a #{exception.class}; retry attempt #{attempt_number}; #{total_delay} seconds have passed."
with_retries(:max_tries => 5, :handler => handler, :rescue => [RuntimeError, ZeroDivisionError]) do |attempt|
  (1 / 0) if attempt == 3
  raise "hey!" if attempt < 5

This will print something like:

Handler saw a RuntimeError; retry attempt 1; 2.9e-05 seconds have passed.
Handler saw a RuntimeError; retry attempt 2; 0.501176 seconds have passed.
Handler saw a ZeroDivisionError; retry attempt 3; 1.129921 seconds have passed.
Handler saw a RuntimeError; retry attempt 4; 1.886828 seconds have passed.

Delay parameters

By default,

will wait about a half second between the first and second attempts, and then the delay time will increase exponentially between attempts (but stay at no more than 1 second). The delays are perturbed randomly. You can control the parameters via the two options
. For instance, you can start the delay at 100ms and go up to a maximum of about 2 seconds:
with_retries(:max_tries => 10, :base_sleep_seconds => 0.1, :max_sleep_seconds => 2.0) { do_the_thing }


In tests, you may wish to test that retries are being performed without any delay for sleeping:

Retries.sleep_enabled = false
with_retries(:max_tries => 100) { raise "Boo!" } # Now this fails fast

Of course, this will mask any errors to the

parameters, so use with caution.


File tickets here on Github.


To run the tests: first clone the repo, then

$ bundle install
$ bundle exec rake test


Retries was created by Harry Robertson and Caleb Spare.

Other contributions from:


Retries is released under the MIT License.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.