我和this other post有类似的问题,我尝试了给定的解决方案,但无济于事。
我的项目是一个Ruby bot,它使用Blather库连接到Jabber服务器。问题是,当服务器出现问题并且Blather生成异常时,整个程序退出,我没有机会捕获异常。
以下是一些显示问题的简单代码。在localhost上没有运行Jabber服务器,因此Blather客户端会抛出异常。我的印象是EM.error_handler {}能够拦截它,但我从未看到**** ERROR
消息,程序就停止了。 :(
#!/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
我认为问题是Blather也使用EventMachine并且可能正在调用EM.stop,这会导致外部EM实例停止。
答案 0 :(得分:5)
异常和异步编程不是朋友,因此处理它们可能很棘手。在同步模型中,可以通过在可能产生异常的代码块上使用rescue
来捕获异常,但是一旦创建了回调方法,该块就需要自己的异常处理,因为它将在该上下文之外运行
希望error_handler
能够捕获您的异常,但是如果您涉及其他线程可能无法捕获它们。
您可以随时使用monkeypatch EventMachine.stop_event_loop
和EventMachine.stop_server
来查看这是否是被调用的方法。
答案 1 :(得分:2)
error_handler捕获在执行事件循环中触发的回调期间发生的异常。在上面的代码崩溃的时候你不会启动循环。 (我假设Blather :: Stream.start而不是上面的Blather :: Stream :: Client.start。)
您可以尝试执行EM.next_tick {Blather :: Stream.start(...)},这会强制它在反应堆循环期间执行。
但是,通常,您不希望在error_handler触发后继续。它基本上是最后一道防线,可以清理任何状态并退出(并打印堆栈跟踪,以便了解应用程序崩溃的原因)。当它触发时你不知道应用程序的当前状态是什么,你不能真正相信状态是正确的或一致的。
理论上,你可以将Blather调用包装在开始/救援中:
begin
Blather::Stream.start(...)
rescue Exception => e
puts e
end
哪个应该为你做的伎俩,你可以坚持一些重试逻辑。
答案 2 :(得分:1)
您可以通过以下方式附加error_handler
:
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