我有一个非常简单的设置来测试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”:
答案 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 :我的提交已合并到官方文档中。