class Tretry

A library for doing retries in Ruby with timeouts, analysis of errors, waits between tries and more.

Constants

VALID_KEYS

Valid keys that can be given as argument for the method 'try'.

Attributes

fails[R]
timeout[RW]
tries[RW]
wait[RW]

Public Class Methods

new(args = {}) click to toggle source
# File lib/tretry.rb, line 21
def initialize(args = {})
  @args = args
  @fails = []
  @before_retry = []

  parse_arguments
end
try(args = {}, &block) click to toggle source

Runs a block of code a given amount of times until it succeeds.

Examples

res = Tretry.try(:tries => 3) do
   #something that often fails
end

puts "Tries: '#{res[:tries]}'."
puts "Result: '#{res[:result}'."
# File lib/tretry.rb, line 17
def self.try(args = {}, &block)
  Tretry.new(args).try(&block)
end

Public Instance Methods

before_retry(&block) click to toggle source
# File lib/tretry.rb, line 29
def before_retry(&block)
  @before_retry << block
end
try(&block) click to toggle source
# File lib/tretry.rb, line 33
def try(&block)
  raise "No block given." unless block
  @block = block

  @tries.times do |count|
    @count = count

    unless first_try?
      # Sleep for a given amount of time if the 'wait'-argument is given.
      sleep(@wait) if @wait

      call_before_retry(error: @error)
      @error = nil
    end

    begin
      # If a timeout-argument has been given, then run the code through the timeout.
      if @timeout
        try_with_timeout
      else
        # Else call block normally.
        @res = @block.call
        @dobreak = true
      end
    rescue Exception => e
      handle_error(e)
    end

    if @doraise
      if @args[:return_error]
        @fails << {error: @error}
        return {
          fails: @fails,
          error: true
        }
      else
        raise @error
      end
    elsif @error
      @fails << {error: @error}
    end

    break if @dobreak
  end

  return {
    fails: @fails,
    result: @res,
    error: false
  }
end

Private Instance Methods

call_before_retry(args) click to toggle source
# File lib/tretry.rb, line 127
def call_before_retry(args)
  @before_retry.each do |before_retry_block|
    before_retry_block.call(args)
  end
end
first_try?() click to toggle source
# File lib/tretry.rb, line 137
def first_try?
  @count == 0
end
handle_error(e) click to toggle source
# File lib/tretry.rb, line 113
def handle_error(e)
  if e.class == Interrupt
    raise e if !@args.key?(:interrupt) || @args[:interrupt]
  elsif e.class == SystemExit
    raise e if !@args.key?(:exit) || @args[:exit]
  elsif last_try? || (@args.key?(:errors) && !@args[:errors].include?(e.class))
    @doraise = e
  elsif @args.key?(:errors) && @args[:errors].index(e.class) != nil
    #given error was in the :errors-array - do nothing. Maybe later it should be logged and returned in a stats-hash or something? - knj
  end

  @error = e
end
last_try?() click to toggle source
# File lib/tretry.rb, line 133
def last_try?
  (@count + 1) >= @tries
end
parse_arguments() click to toggle source
# File lib/tretry.rb, line 87
def parse_arguments
  #Validate given arguments and set various variables.
  raise "Expected argument to be a hash." unless @args.is_a?(Hash)

  @args.each do |key, val|
    raise "Invalid key: '#{key}'." unless VALID_KEYS.include?(key)
  end

  @args[:tries] ||= 3
  @tries = @args[:tries].to_i
  @wait = @args[:wait] ? @args[:wait] : nil
  @timeout = @args[:timeout] ? @args[:timeout].to_f : nil
end
try_with_timeout() click to toggle source
# File lib/tretry.rb, line 101
def try_with_timeout
  begin
    require "timeout"
    Timeout.timeout(@timeout) do
      @res = @block.call
      @dobreak = true
    end
  rescue Timeout::Error => e
    handle_error(e)
  end
end