in which an opportunity for exceptional confusion presents itself
source link: https://technomancy.us/114
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
So I've noticed there seems to be a fair amount of confusion in the Ruby world about exception hierarchies. A number of libraries I use happen to use them in ways that cause problems—usually in ways that surface at the worst possible times near the end of long batch operations. So here's a little primer to refresh your memory and hopefully save some of my sanity if I ever use one of your gems.
Exception
is the root class for the whole exception
hierarchy. I see a lot of code that subclasses Exception
for regular non-fatal exceptions. It's not obvious, but this is
really not how it's meant to be used. Imagine you are building a
restful interface. The following code will bring down the
application:
# This is wrong! Inherit from StandardError. class GetSomeRest < Exception; end begin if (7 .. 11).include? Time.now.hour perform_restful_operation else raise GetSomeRest end rescue puts 'You really should not stay up so late.' end
This is because rescue
will only capture errors that
descend from StandardError
by default. We should be
subclassing StandardError
here, as well as for anything
else that's non-fatal. Save Exception
subclasses for very
serious things. Running out of memory should raise an
Exception
. When a user presses control-c, it raises
Interrupt
, which is descended directly from
Exception
rather than StandardError
. Sending a
Unix kill signal to a process does the same thing. If you rescue
Exception
or Interrupt
, then you have to resort
to kill -9
to stop your application externally, leaving
it with no chance to clean up after yourself.
Unfortunately, we live in an imperfect world, and we have to deal with libraries that misuse the exception hierarchy. The first thing you should do when you encounter one of these misuses is submit a patch to the offending library. (You could even include a link to this post.) But it's not always possible to get it fixed, so here's the workaround I've been using:
begin perform_possibly_problematic_process rescue Exception => e raise e unless e.is_a? StandardError or e.is_a? GetSomeRest @log.warn e.message # or whatever end
If you're not sure of all the problematic Exception
s a
piece of code could raise, you could just rescue Exception
and re-raise e
if it's an Interrupt
, but this
might swallow some other legitimate serious problems, so it's best
to be specific.
Tell your friends to use Ruby's exception hierarchy as it was intended! Update: Don't feel bad if you didn't know this, apparently even the Lucky Stiff himself has fallen into this trap.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK