Skip to content

Instantly share code, notes, and snippets.

@jaimeiniesta
Forked from raul/retry_upto.rb
Created October 7, 2011 14:58
Show Gist options
  • Save jaimeiniesta/1270450 to your computer and use it in GitHub Desktop.
Save jaimeiniesta/1270450 to your computer and use it in GitHub Desktop.
retry_upto.rb
# This allows to use a numeric or a lambda
def retry_upto(max_retries = 1, options = {})
begin
return yield if ((max_retries -= 1) > 0)
rescue (options[:rescue_only] || Exception)
if options[:patience]
if options[:patience].is_a?(Numeric)
options[:wait] = options[:wait] * options[:patience]
else
options[:wait] = options[:patience].call(options[:wait])
end
end
puts "retrying... #{Time.now} (sleeping #{options[:wait]})"
sleep(options[:wait] || 0)
retry
end
yield
end
###########
# Examples
###########
# If a number is passed to the :patience option, it will be used as a multiplier
retry_upto(3, :wait => 1, :patience => 2) do
puts 1 / 0
end
# If a lambda is passed, it will be called passing it the :wait option value as the argument
retry_upto(3, :wait => 2, :patience => lambda {|x| rand(5)}) do
puts 1 / 0
end
# Ruby `retry` with steroids:
#
# - retry up to 5 times without waiting between them and retrying after any exception
#
# retry_upto(5) do ... end
#
# - retry up to 5 times, waiting 2 seconds between retries and retrying after any exception
#
# retry_upto(5, :wait => 2) do ... end
#
# - retry up to 5 times, waiting 1 second initially and having increasing patience (2, 4, 8, ...)
#
# retry_upto(5, :wait => 1, :patience => 2) do ... end
#
# - retry up to 5 times, waiting 1 second initially and having decreasing patience (0.5, 0.25, 0.125, ...)
#
# retry_upto(5, :wait => 1, :patience => 0.5) do ... end
#
# - retry up to 5 times without waiting between retries, retrying only after a ZeroDivisionError
#
# retry_upto(5, :rescue_only => ZeroDivisionError) do ... end
#
# - retry up to 5 times, waiting 2 seconds between retries, retrying only after a ZeroDivisionError
#
# retry_upto(5, :wait => 2, :rescue_only => ZeroDivisionError) do ... end
def retry_upto(max_retries = 1, options = {})
begin
return yield if ((max_retries -= 1) > 0)
rescue (options[:rescue_only] || Exception)
options[:wait] *= options[:patience] if options[:patience]
sleep(options[:wait] || 0)
retry
end
yield
end
# A variant that allows to pass a lambda as a patience factor, instead of an integer multiplier.
# Allows for more complex cases, although maybe totally unneeded.
##########
def retry_upto(max_retries = 1, options = {})
begin
return yield if ((max_retries -= 1) > 0)
rescue (options[:rescue_only] || Exception)
options[:wait] = options[:patience].call(options[:wait]) if options[:patience]
sleep(options[:wait] || 0)
retry
end
yield
end
##########
# Example:
retry_upto(10, :wait => 2, :patience => lambda {|x| x*x}) do
puts 1 / 0
end
retry_upto(10, :wait => 2, :patience => lambda {|x| Math.sqrt(x)}) do
puts 1 / 0
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment