如何在 EventMachine 实现中捕获异常?

Posted

技术标签:

【中文标题】如何在 EventMachine 实现中捕获异常?【英文标题】:How do you catch exceptions in an EventMachine implementation? 【发布时间】:2011-12-07 13:49:15 【问题描述】:

我遇到了与this other post 类似的问题,我尝试了给定的解决方案,但无济于事。

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

这里有一些显示问题的简单代码。本地主机上没有运行 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 实例停止。

【问题讨论】:

【参考方案1】:

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

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

您总是可以对EventMachine.stop_event_loopEventMachine.stop_server 进行monkeypatch 以查看是否是被调用的方法。

【讨论】:

嗯...这不是最佳解决方案。 error_handler 应该 捕捉到这些东西,但不是出于某种原因。我会给猴子补丁选项一试,看看我是否可以通过这种方式“解决”我的问题。 :// 猴子补丁只是为了查看这些方法是否被调用,因为之后不再需要它们。【参考方案2】:

error_handler 捕获在事件循环中触发的回调执行期间发生的异常。您不会在上述代码崩溃时开始循环。 (我假设是 Blather::Stream.start 而不是上面的 Blather::Stream::Client.start)。

您可以尝试执行 EM.next_tick Blather::Stream.start(...) ,这将强制它在反应器循环期间执行。

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

理论上,您可以将 Blather 调用包装在 begin/rescue 中:

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

这应该对你有用,然后你可以坚持一些重试逻辑。

【讨论】:

【参考方案3】:

您可以通过这种方式附加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

【讨论】:

以上是关于如何在 EventMachine 实现中捕获异常?的主要内容,如果未能解决你的问题,请参考以下文章

Android 中如何捕获未捕获的异常

Servlet过滤器——异常捕获过滤器

.Net 6.0全局异常捕获

你如何实现重试捕获?

ajax请求后台代码,如何实现后台抛出异常在前台捕获异常:如后台抛出throw exception("该帖子已被删除")

多线程情况下如何捕获线程中的异常?