Easy to use DSL to retry code if an exception is raised.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.



Retryable is an easy to use DSL to retry code if an exception is raised. This is especially useful when interacting with unreliable services that fail randomly.


gem install retryable-rb

# In your ruby application
require 'retryable'

Using Retryable

Code wrapped in a Retryable block will be retried if a failure occurs. As such, code attempted once, will be retried again for another attempt if it fails to run.

# Include Retryable into your class
class Api
  include Retryable

  # Use it in methods that interact with unreliable services
  def get
    retryable do
      # code here...

By default, Retryable will rescue any exception inherited from Exception, retry once (for a total of two attempts) and sleep for a random amount time (between 0 to 100 milliseconds, in 10 millisecond increments). You can choose additional options by passing them via an options Hash.

retryable :on => Timeout::Error, :times => 3, :sleep => 1 do
  # code here...

This example will only retry on a Timeout::Error, retry 3 times (for a total of 4 attempts) and sleep for a full second before each retry. You can also specify multiple errors to retry on by passing an array.

retryable :on => [Timeout::Error, Errno::ECONNRESET] do
  # code here...

You can also have Ruby retry immediately after a failure by passing false as the sleep option.

retryable :sleep => false do
  # code here...

Retryable also allows for callbacks to be defined, which is useful to log failures for analytics purposes or cleanup after repeated failures. Retryable has three types of callbacks: then, finally, and always.

then: Run every time a failure occurs.

finally: Run when the number of retries runs out.

always: Run when the code wrapped in a Retryable block passes or when the number of retries runs out.

The then and finally callbacks pass the exception raised, which can be used for logging or error control. All three callbacks also have a handler, which provides an interface to pass data between the code wrapped in the Retryable block and the callbacks defined.

Furthermore, each callback provides the number of attempts, retries and times that the wrapped code should be retried. As these are specified in a Proc, unnecessary variables can be left out of the parameter list.

then_cb = Proc.new do |exception, handler, attempts, retries, times|
  log "#{exception.class}: '#{exception.message}' - #{attempts} attempts, #{retries} out of #{times} retries left."}

finally_cb = Proc.new do |exception, handler|
  log "#{exception.class} raised too many times. First attempt at #{handler[:start]} and final attempt at #{Time.now}"

always_cb = Proc.new do |handler, attempts|
  log "total time for #{attempts} attempts: #{Time.now - handler[:start]}"

retryable :then => then_cb, :finally => finally_cb, :always => always_cb do |handler|
  handler[:start] ||= Time.now

  # code here...

If you are using Retryable once or outside of a class, you can also use it via its module method as well.

Retryable.retryable do
  # code here...


Retryable was inspired by code written by Michael Celona and later assisted by David Malin.