如何在EventMachine实现中捕获exception?

我对这个post有类似的问题,我尝试了给定的解决方案,但无济于事。

我的项目是一个Ruby bot,它使用Blather库连接到Jabber服务器。 问题是,当服务器出现问题并且Blather生成exception时,整个程序退出,我没有机会捕获exception。

这是一些显示问题的简单代码。 在localhost上没有运行Jabber服务器,因此Blather客户端抛出exception。 我的印象是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实例停止。

exception和异步编程不是朋友,因此正确处理它们可能很棘手。 在同步模型中,可以通过对可能产生exception的代码块使用rescue来捕获exception,但是一旦创建了回调方法,该块就需要自己的exception处理,因为它将在该上下文之外运行。

希望error_handler能捕获您的exception,但如果您有其他涉及的线程可能无法捕获它们。

您可以始终monkeypatch EventMachine.stop_event_loopEventMachine.stop_server来查看是否正在调用该方法。

error_handler捕获在执行事件循环中触发的回调期间发生的exception。 在上面的代码崩溃的时候你不会启动循环。 (我假设Blather :: Stream.start而不是上面的Blather :: Stream :: Client.start)。

您可以尝试执行EM.next_tick {Blather :: Stream.start(…)},这会强制它在reactor循环期间执行。

但是,一般情况下,您不希望在error_handler触发后继续。 它基本上是最后一道防线,可以清理任何状态并退出(并打印堆栈跟踪,以便了解应用程序崩溃的原因)。 当它触发时你不知道你的应用程序的当前状态是什么,你不能真正相信状态是正确的或一致的。

理论上,您可以将Blather调用包装在开始/救援中:

 begin Blather::Stream.start(...) rescue Exception => e puts e end 

哪个应该为你做,你可以坚持一些重试逻辑。