@suggestions   @rss   @archive   @codeforpeople.com     @random   @radio[:m3u|:pls|:ruby]   @family   @neighbors  @twitter 



[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

  n = 0

  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

  require timeout

  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

  require retry_on_timeout

  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 RUBYOPT=rretry_on_timeout
  export RUBY_TIMEOUT_TIMES=3

and whammo

  cfp:~ > echo $RUBYOPT
  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!

Comments (View)
blog comments powered by Disqus