How do you catch exceptions in an EventMachine implementation?

余生颓废 提交于 2019-12-07 03:11:39

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!