16 February 2012

Mind your rescue magic

Rescue someone unwilling to look after himself, and he will cling to you like a dangerous illness.

--Mason Cooley
It is always a good practice to rescue exceptions in Ruby, but be aware that, keep best the practices all times even when you are doing your rescue magic.

Let us take a look at the following code:

begin
  HTTParty.get(@url, :timeout => 5)
rescue
  "Time out!"
end

It is supposed to return the "Time Out!" string, but instead it just throws out a Ruby error. Obviously my magic couldn't rescue me for some reason which is unknown to me. I muddled around for a while, it just would not work for me.

Did a bit digging on the net and I found a few articles which pulled me out of the mud. One is "Ruby Exceptions" from Ruby Learning, the other is "Ruby Timeout::Error" from Marcin Ciunelis. So I updated my code to the following, and it worked:

begin
  HTTParty.get(@url, :timeout => 5)
rescue Exception=>exception
  "#{exception.inspect}"
end


So, in one word: Rescue will only rescue StandardError by default, and Timeout error is not a StandardError, depending on the Ruby version you are using. The following is an overview of the Ruby Exception structure:

Digging deeper, I found something even more interesting. If anyone of you are using different Rubies in different projects, you should be aware of this:

#rvm 1.8.7
#irb
#require 'timeout'
>> Timeout::Error.ancestors
=> [Timeout::Error, Interrupt, SignalException, Exception, Object, Kernel]
#rvm 1.9.3
#irb
#require 'timeout'
>> Timeout::Error.ancestors
=> [Timeout::Error, RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
#rvm jruby-1.6.5
#irb
#require 'timeout'
>> Timeout::Error.ancestors
=> [Timeout::Error, Interrupt, SignalException, Exception, Object, Kernel]
You see the difference? Jruby 1.6 is supposed to be the equivalent of MRI Ruby 1.9, but the Timeout Exception structure is the same with 1.8.

It got me. Did it get you?

Hope this helps.


Cheers,
Felix

No comments:

Post a Comment