def func
some code...
rescue x,y,z
do something...
I have a function where I'm trying to rescue an exception and then do something inside of rescue. I want to understand how to handle in case there is an exception again inside of the rescue block. This is a corner case and it is definitely necessary.
In case there is an exception again inside of rescue I want to be able to handle it. Any suggestions appreciated.
You can simply nest a rescue exception inside another rescue exception and you can do so using a number of different approaches depending on the situation but here are a couple:
begin
do_something
rescue
do_something_else rescue do_this_instead
end
OR
begin
do_something
rescue
begin
do_something_else
rescue
do_this_instead
end
end
Related
I would like the exceptions to be rescued, raised and rescued again using exception hierarchy syntax like the below snippet..
class InnerCustomError < StandardError
def initialize(msg = "inner")
super
end
end
class OuterCustomError < StandardError
def initialize(msg = "outer")
super
end
end
begin
raise InnerCustomError
rescue InnerCustomError
raise OuterCustomError
rescue OuterCustomError, StandardError => e
e.message
end
but this raises ==> OuterCustomError (outer)
why is this behaviour? Instead I would like it to be rescued ..
I understand nested begin end blocks like below is used to achieve the same,
begin
begin
raise InnerCustomError
rescue InnerCustomError
raise OuterCustomError
end
rescue OuterCustomError, StandardError => e
e.message
end
also I understand there are performance impacts with this idea but I would like to understand how is the former interpreted?
but this raises OuterCustomError. Why is this behaviour?
Because that's how this construct works. The first matching rescue is selected as a handler for the exception and the result of this handling will be the result of the begin/rescue. If the handler raises and you want to catch that new exception, you need to add another layer of begin/rescue, exactly like you show in the last snippet.
It is described in the documentation here.
begin
do_something
rescue
Logger.write ...
...error handling...
end
The problem is that it is possible that the code inside the rescue raises an exception. For this use case, I want to suppress it.
So, how to wrap the rescue in a rescue to suppress the Exception?
You said it yourself
wrap the rescue in a rescue
Exception Inception
There's no special way other than wrapping blocks of code in a begin rescue end block:
begin
do_something
rescue
begin
Logger.write ...
rescue
...error handling...
end
end
...unless you're using ActiveSupport: http://api.rubyonrails.org/classes/Kernel.html#method-i-suppress
suppress(Exception) do
# all exceptions will be suppressed
end
..but it isn't a plain Ruby thing and I noticed you didn't add a rails tag to your question. Though, you can implement suppress yourself. Or, just, here take this:
def suppress(*exception_classes)
yield
rescue *exception_classes
end
Use that in your rescue:
begin
do_something
rescue
Logger.write ...
suppress Exception do
...error handling...
end
end
In plain old Ruby it's got to be rescues all the way down (and indeed, suppress is just a nested rescue) but let me just state that it's a bad idea to rescue all exceptions, in essence, by not being explicit about what exception you're rescuing, in other words, by not passing an exception class argument to rescue you're implicitly rescuing StandardError which is the superclass to most exceptions (more info here). This can lead to hard to find bugs.
begin
rescue
end
..is the same as:
begin
rescue StandardError
end
It's much better to know what exception you're rescuing and be explicit about it:
begin
rescue SomeApiError => e
# do something when this specific exception occurs
end
With that figured out you can use a cascade strategy to rescue your exceptions:
begin
# do the thing
rescue SomeApiError => e
# specific rescue
rescue SomeOtherError => e
# more broad error handling
rescue
# catch all rescue
end
With the above only the rescue clause that matches the exception being raised will run however, code in a rescue block won't be rescued by subsequent rescues, only the code in the begin block is rescuable.
If you want to have a block of code that always runs even in the event of an exception, use the ensure keyword:
begin
# code
rescue => e
# rescue code
ensure
# this block will always run exception or not
end
Here's what I'm trying to do:
class Foo
def foo
raise "lol noob"
end
# ... many other methods here ...
rescue StandardError => e
puts "error caught: #{e}"
end
Foo.new.foo
RuntimeError: lol noob
from (pry):45:in `foo'
As you can see, this does not work.
What I'm trying to avoid is to put a rescue block into every single method, given that they're many. Is it possible? If not, what's the best practice?
TL;DR
In Ruby, you generally have to wrap the caller with rescue, rather than the receiver.
Explanation
It's likely that you're finding this behavior surprising because you're not thinking of classes as executable code. A rescue clause in a class definition will capture exceptions raised while the class is being interpreted. Consider the following example:
class Foo
raise 'bar'
rescue
'Rescued!'
end
#=> "Rescued!"
Here, the rescue clause works because the exception is raised while the class code is executing. However, some Foo#bar method wouldn't normally get rescued by this clause (except possibly while being defined) because Foo is no longer the caller, it's the receiver.
A rescue clause on the class will catch exceptions raised when the class itself is being defined. However, to rescue within a method at run-time, you need to rescue within the caller (in this case, the #bar method) as follows:
class Foo
def bar
raise 'method exception'
rescue
'Rescued method exception.'
end
end
Foo.new.bar
#=> "Rescued method exception."
It would make no sense to have a common rescue block for a class, each method does different things right? How would you handle the variety of errors all in the same way? Error handling is just as much part of the logic as the "main" part of the method(s).
There's no silver bullet here, you rescue where you need to, and do what is needed when it is needed.
The Exceptional Ruby book may be of interest if you want to learn some common best practices.
If you're absolutely sure that the only error handling you need to do is log out errors, you can abstract away some of the repetitive error logging by defining a helper method that takes in a block and do your error handling there.
For example,
class Foo
def foo
handle_exception do
raise "lol noob"
end
end
def bar
handle_exception do
raise "rofl"
end
end
def handle_exception
yield
rescue => e
puts "error caught: #{e}"
end
end
Foo.new.foo # error caught: lol noob
Foo.new.bar # error caught: rofl
This has the benefit that later on you decide that want some alternate behavior, ie adding in a backtrace, you only have to touch one line of code:
def handle_exception
yield
rescue => e
puts "error caught: #{e}\n#{e.backtrace.join("\n")}"
end
I am trying to figure out how to make the EventMachine::Deferrable callbacks not raise any exceptions. Instead of having begin ... rescue in every callback block, I am trying to wrap the block somehow with a method call so that the method rescues the exceptions:
require 'eventmachine'
def to_proc
proc
rescue Exception => e
puts "e=#{e}"
end
EventMachine::run {
d = EventMachine::DefaultDeferrable.new
f = to_proc {raise 'error'}
d.callback &f
EventMachine.next_tick {d.succeed}
}
this does not work of course. I would appreciate any help.
At the statement d.callback &f, to_proc is called. The exception you're trying to catch down at d.succeed can't be caught, because we are already outside the context of your exception handling.
I'm not actually sure what error you're trying to catch. If it's an error in what you have EventMachine doing, you can create an #errBack to catch them. If you are really trying to catch exceptions that only happen in your callbacks, then you should probably just write the exception handlers in the callbacks (for the specific exceptions you expect!).
However, if you really want to catch all errors in all procs, you need to override call in class Proc:
# Note this code hasn't been tested and is only provided as an example
class Proc
alias_method :old_call, :call
def call(*args)
begin
old_call(*args)
rescue Exception => e
# Handle exception
end
end
end
I do not recommend this approach however
I don't understand why this code is not working properly:
def test
raise Exception.new 'error'
end
def caller
begin
test
rescue =>e
puts e.message
end
end
caller
I want to catch the test exception in the caller method, but it seems that the caller method is not catching anything.
The reason your code doesn't work is because rescue without an explicitly stated exception type only catches StandardError, which is a subclass of Exception. Since you're raising Exception, which is higher than StandardError, your rescue doesn't catch it.
Generally you want to use more specific exceptions, and you almost never need to use Exception over StandardError.
This, for example, works fine:
begin
raise StandardError.new 'Uh-oh!'
rescue => e
p e.message
end
#=> Uh-oh!
You should specify what kind of exceptions you'd like to rescue. Try
rescue Exception => e
Jan beat me to it, but...
When you use the => var syntax with exception, you must specify what kind of exception you want to rescue. The base class for all exceptions is Exception, so it will work if you change that to rescue Exception => e. Also, when what you're rescuing from is the entire body of a method, you don't need an explicit begin...end block...
def test
raise Exception.new 'error'
end
def caller
test
rescue Exception =>e
puts e.message
end
caller()