[Ruby] automatically retry on timeout errors
this other day a friend asked how to globally alter a ton of command line scripts to automatically do a couple of retries on Timeout::Error. so basically a bunch of scripts that looked like this
Timeout.timeout(1) do
puts “sleeping #{ n += 1 }…”
sleep 1.1
end
so stuff that blows up with Timeout::Error - but we want an automatic retry.
this first step was to write a library that alters the built-in timeout.rb library to support this behaviour. here it is - notice that, by default, it does not do any retries - it has to be configured to do that
module Timeout
class « Timeout
attr_accessor(’times’)
alias_method(’timeout_without_retry’, ‘timeout’) #unless methods.include?(‘timeout_without_retry’)
def timeout(*args, &block)
times = Timeout.times
begin
timeout_without_retry(*args, &block)
rescue Timeout::Error => e
times -= 1
times <= 0 ? raise : retry
end
end
end
Timeout.times = Integer(ENV[’RUBY_TIMEOUT_TIMES’] || 0)
end
of course we could alter all the scripts to use this library like so
Timeout.times = 3
n = 0
Timeout.timeout(1) do
puts “sleeping #{ n += 1 }…”
sleep 1.1
end
and that would certainly work. but it would also suck ass. instead, we can globally configure the environment to do two things: to automatically require this library and to set a default number of retries. this will work
export RUBY_TIMEOUT_TIMES=3
and whammo
rretry_on_timeout
cfp:~ > echo $RUBY_TIMEOUT_TIMES
3
cfp:~ > cat a.rb
n = 0
Timeout.timeout(1) do
puts “sleeping #{ n += 1 }…”
sleep 1.1
end
cfp:~ > ruby a.rb
sleeping 1…
sleeping 2…
sleeping 3…
/opt/local/lib/ruby/1.8/timeout.rb:54: execution expired (Timeout::Error)
from /opt/local/lib/ruby/1.8/timeout.rb:56:in `timeout_without_retry’
from ./retry_on_timeout.rb:11:in `timeout’
from a.rb:3
cfp:~ > export RUBY_TIMEOUT_TIMES=0
cfp:~ > ruby a.rb
sleeping 1…
/opt/local/lib/ruby/1.8/timeout.rb:54: execution expired (Timeout::Error)
from /opt/local/lib/ruby/1.8/timeout.rb:56:in `timeout_without_retry’
from ./retry_on_timeout.rb:11:in `timeout’
from a.rb:3
obviously one would have to install this library at the system level for that to work. oh, lal - you owe me beer!