ActiveSupport :: Notifications应该是异步的吗?

时间:2013-05-20 14:04:48

标签: ruby ruby-on-rails-3

我有一个非常简单的设置来测试rails3 ActiveSupport::Notifications。 通过阅读文档,ActiveSupport::Notifications.subscribe位应该异步执行它的操作。显然事实并非如此。

示例:

ActiveSupport::Notifications.subscribe "some.channel" do |name, start, finish, id, payload|
  # do expensive task
  sleep(10)
end

ActiveSupport::Notifications.instrument "some.channel" #=> will return 10 seconds later

我的印象是ActiveSupport::Notifications.instrument "some.channel"会马上回来让昂贵的任务做昂贵的事情。否则,我可以直接调用昂贵的任务,而无需使用订户。

该文档还说明可能有多个订阅者。在这种情况下,我会被阻止,直到所有其他订阅者执行他们的代码。

这是对的吗?如果是,有人可以解释http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html的这一行是什么意思吗?

The block will be called asynchronously whenever someone instruments “render”:

1 个答案:

答案 0 :(得分:9)

你是对的。 ActiveSupport::Notifications.instrument不会异步/同时调用订阅者或任何类型的订阅者。

如果您遵循代码,您会发现#instrument调用指导者,而指导者调用通知程序。通知程序是ActiveSupport::Notifications::Fanout的一个实例,它通过#publish方法向所有侦听器发送通知:

def publish(name, *args)
  listeners_for(name).each { |s| s.publish(name, *args) }
end

侦听器/订阅者的#publish方法也不是异步的:

def publish(message, *args)
  @delegate.call(message, *args)
end

所有这一切都是调用订户提供的块。同步。

那么为什么文档声明The block will be called asynchronously whenever someone instruments “render”Notifications ships with a queue implementation that consumes and publish events to log subscribers in a thread

看起来原始实现是异步的,他们忘了更新文档。如果查看change history for fanout.rb,您可以看到2010年的一些提交,其中实现已更改为同步队列。线程实现可能过于复杂且容易出错。你甚至可以看到剩下的vestiges

# This is a sync queue, so there is no waiting.
def wait
end

这似乎是提交docrails的好候选人。

在任何情况下,即使实现是异步的,您也可能希望任何长时间运行的代码进入队列(例如resque)并由后台工作程序处理。这样,您的webapp工作进程就不会处理长时间运行的任务,而不是处理请求。

更新:从11个月前发现commit,删除了有关非同步通知的错误信息。但是,队列在线程中运行的错误信息仍然存在。

更新2 :我committed向docrails修改有关在线程中运行的队列的信息。

更新3 :我的提交已合并到官方文档中。