Retrying code blocks in Ruby (on exceptions, whatever)

I am not certain whether the ability to retry a code block when encountering exceptions was a feature available in Ruby, but I certainly couldn’t find anything on that topic (what I did find were mostly about the retry keyword for iterator loops).

Before you ask why I need this, the motivation for this was because I was getting intermittent HTTP errors (503s mostly) trying to connect to a web service. Turns out it’s really easy in Ruby to implement a retryable method that does something like this:

retryable(:tries => 5, :on => OpenURI::HTTPError) do
  open('http://example.com/flaky_api')
  # Code that mashes up stuff for your "social networking" site.
end

Here are the Kernel#retryable specs (pastie).

And the code:

# Options:
# * :tries - Number of retries to perform. Defaults to 1.
# * :on - The Exception on which a retry will be performed. Defaults to Exception, which retries on any Exception.
#
# Example
# =======
#   retryable(:tries => 1, :on => OpenURI::HTTPError) do
#     # your code here
#   end
#
def retryable(options = {}, &block)
  opts = { :tries => 1, :on => Exception }.merge(options)

  retry_exception, retries = opts[:on], opts[:tries]

  begin
    return yield
  rescue retry_exception
    retry if (retries -= 1) > 0
  end

  yield
end

It’s not hard to implement the same for checking return values as well, i.e.

retryable_deluxe(:tries => 5, :on => { :return => nil }) { puts "working..." }

retryable_deluxe(:on => { :exception => StandardError, :return => nil }) do
  # your code here
end

Ruby is nice.

9 Comments & TrackBacks (Add yours)

The paper doll icon that precedes each comment is an idea conceived by Vanessa Tan.

Paper doll icon
rubylicio.us's Gravatar

Good idea and nice little snippet, I usually tend to skip conditional retries, for no better reason then it feels like it clutters up my code alot … which is a somewhat lame reason now that I think about it :)

Wonder if this could be built into “retry” itself somehow ..

begin
  open('http://example.com/flaky_api')
rescue OpenURI::HTTPError, :retries => 5
  ## blah, errorreporting etc
end

Posted by: rubylicio.us on January 14, 2008 8pm

Paper doll icon
rubylicio.us's Gravatar

I ofcourse meant built into “rescue”, not “retry” in the above post.

Posted by: rubylicio.us on January 14, 2008 8pm

Paper doll icon
Chu Yeow's Gravatar

Yup exactly - I hated having to put conditionals in there for retries. Thankfully for Ruby blocks, we can abstract that considerably :)

That sounds really nice, if we could monkey patch rescue, but I think it could be hard since rescue’s a language keyword.

Posted by: Chu Yeow on January 14, 2008 8pm

Paper doll icon
macournoyer's Gravatar

very nice, I like your retryable method!

Posted by: macournoyer on January 14, 2008 10pm

Paper doll icon
Geoff Buesing's Gravatar

I like this idea.

I think you could avoid the double yield in your implementation by using Ruby’s “retry” method:


rescue SomeError
tries -= 1
retry if tries > 0

Posted by: Geoff Buesing on January 15, 2008 1am

Paper doll icon
Jeremy McAnally's Gravatar

The retry keyword works for exceptions also. You could easily write a little helper to handle the retry counter, etc.

Posted by: Jeremy McAnally on January 15, 2008 2am

Paper doll icon
Chu Yeow's Gravatar

You’re right, Geoff and Jeremy! I wasn’t aware the retry keyword worked for exceptions as well. I’ve updated the code :).

Posted by: Chu Yeow on January 15, 2008 9am

Paper doll icon
www.hans-eric.com » Blog Archive » Loop Abstractions in D's Gravatar

[…] with Ruby is the natural way in which you can hide looping constructs with descriptive names. Like the retryable example that Cheah Chu Yeow gives on his […]

Posted by: www.hans-eric.com » Blog Archive » Loop Abstractions in D on January 18, 2008 5am

Paper doll icon
Loop Abstractions in D revisited's Gravatar

[…] I showed you how we could make loop constructs abstract, in a similar way which is common in Ruby. The example I used as a model was the retryable method from Cheah Chu Yeow. His version is customizable in a way that let you […]

Posted by: Loop Abstractions in D revisited on January 31, 2008 11pm

You can subscribe to the RSS feed for comments on this post.

Post a comment

(required)

(required, but never displayed)


You can format your comments using XHTML. Your email address will not be displayed or used for nefarious purposes.

Only following tags are allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>