问题
I have a similar problem to this other post and I've tried the given solutions but to no avail.
My project is a Ruby bot that uses the Blather library to connect to a Jabber server. The problem is that when there is a problem with the server and Blather generates an exception the whole program exits and I have no opportunity to catch the exception.
Here is some simple code that shows the problem. There is no Jabber server running on localhost so the Blather client throws an exception. I was under the impression that EM.error_handler{} would be able to intercept it but I never see the **** ERROR
message and the program just stops. :(
#!/usr/bin/env ruby
require 'rubygems'
require 'blather/client/client'
EM.run do
EM.error_handler { puts " **** ERROR " }
Blather::Stream::Client.start(
Class.new {
}.new, 'echo@127.0.0.1', 'echo')
end
I think the problem is that Blather also uses EventMachine and maybe is calling EM.stop, which causes the external EM instance to stop.
回答1:
Exceptions and asynchronous programming are not friends, so they can be tricky to handle properly. In the synchronous model, an exception can be caught by using rescue
on a block of code that may produce exceptions, yet once you create a callback method, that block needs its own exception handling since it will run outside of that context.
Hopefully the error_handler
will catch your exception, but if you have other threads involved that may not be able to capture them.
You could always monkeypatch EventMachine.stop_event_loop
and EventMachine.stop_server
to see if that's the method being called.
回答2:
The error_handler catches exceptions that happen during the execution of callbacks triggered in the event loop. You won't have started the loop at the point the above code is crashing. (I'm assuming that is Blather::Stream.start instead of Blather::Stream::Client.start above).
You could try doing EM.next_tick { Blather::Stream.start(...) } which will force it to execute during the reactor loop.
But, in general, you don't want to be continuing after the error_handler has fired. It's basically a line of last defense for you to cleanup any state and exit (and print a stack trace so you know why the application crashed). When it fires you have no idea what the current state of your application is in and you can't really trust the state to be correct or consistent.
In theory, you can just wrap the Blather call in a begin/rescue:
begin
Blather::Stream.start(...)
rescue Exception => e
puts e
end
Which should do the trick for you, you could then stick in some retry logic.
回答3:
You can attach the error_handler
this way:
require 'eventmachine'
EM.run do
# your stuff
end
# Outside `EM.run`
EM.error_handler do |e|
# Then you can do something like these:
puts e.message
puts e.inspect
puts e.backtrace.join("\n")
end
来源:https://stackoverflow.com/questions/8416349/how-do-you-catch-exceptions-in-an-eventmachine-implementation