2013-05-20 23 views
3

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

例子:

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

这个railscast可以帮助你更好地理解发生了什么http://railscasts.com/episodes/249-notifications-in-rails-3 – jamesc

+0

我看了好几次。 Ryan在他的用户中没有做耗时的任务,所以他没有机会提及使用'instrument'阻止 – Oktav

回答

7

你说得对。 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工作进程不会处理长时间运行的任务,而不是处理请求。

UPDATE:在11个月前发现commit,它删除了关于异步通知的错误信息。但是,队列在线程中运行的错误信息仍然存在。

更新2:我committed docrails修复关于线程中运行队列的信息。

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

+0

这个解释很多。谢谢。我没有详细了解文件是否过时。我已经在我的应用中使用了sidekiq,我正在考虑这样做,但我需要首先弄清楚问题。同时,我只是将代码放在'Thread.new {}'块中的订阅块中。非常丑陋,但会尽快修复。 – Oktav

+0

稍作澄清:docrails不需要拉请求。文档PR应该直接进入rails/rails。 docrails的目的是让许多贡献者直接提交访问权限来更新文档,然后定期将这些更改推到rails/rails上。 – Peeja

+0

好点,我会更新我的答案。 – davogones