我一直在寻找使用ActionController :: Live触发服务器端事件的方法,而无需使用轮询。似乎唯一有记录的直播的酒吧/子解决方案是使用Redis,但我真的很想使用目前拥有的堆栈。我遇到了ActiveSupport ::通知,这似乎可以做我想要的。
但是,当我几乎将其使用Redis时,Live会抛出一个ioError,而流则关闭。我没有看到为什么会发生这种情况的任何正当理由。
例如,这可能有效:
def stream
response.headers['Content-Type'] = 'text/event-stream'
redis = Redis.new
redis.subscribe('namespaced:stream') do |on|
response.stream.write "hello worldn"
end
rescue IOError
# Client Disconnected
ensure
response.stream.close
end
但是,当我尝试此操作时,我会收到一个IO错误:
def stream
response.headers['Content-Type'] = 'text/event-stream'
ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
response.stream.write "hello worldn"
end
rescue IOError
# Client Disconnected
ensure
response.stream.close
end
我真的不知所措。服务器日志中的任何内容都没有表示实际问题,并且通知订阅否则可行。我可以说,因为即使我遇到了IO错误,也可以在" process_action.action_controller"通知时订阅将字符串放到控制台上。
当没有发生通知时,连接工作正常,但是一旦有通知(我认为应该在流中写" Hello World"),我就会遇到那个愚蠢的IO错误。<<<<<</p>
顺便说一句,我确实计划仪器自己的通知;仅使用现有通知进行测试更容易。
哦,这是我访问使用流控制器方法的路线时终端中发生的情况的副本:
IOError (closed stream):
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_dispatch/http/response.rb:76:in `write'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/live.rb:47:in `write'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/live.rb:135:in `rescue in block in process'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/live.rb:145:in `block in process'
IOError (closed stream):
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_dispatch/http/response.rb:76:in `write'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/live.rb:47:in `write'
/home/benjamin/Desktop/workspace/fremote/app/controllers/remotes_controller.rb:25:in `block in show'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/fanout.rb:125:in `call'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/fanout.rb:125:in `finish'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/fanout.rb:40:in `block in finish'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/fanout.rb:40:in `each'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/fanout.rb:40:in `finish'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:36:in `finish'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:25:in `instrument'
/usr/local/lib/ruby/gems/2.0.0/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159:in `instrument'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/abstract_controller/base.rb:136:in `process'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/abstract_controller/rendering.rb:44:in `process'
/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.2/lib/action_controller/metal/live.rb:132:in `block in process'
我很抱歉,如果我误解了任何术语,因为我是SSES和Rails的新手,所以我非常感谢您对此的任何帮助。
编辑:如果您需要知道,我正在使用以下内容:
- Rails 4.0.2
- Ruby 2.0.0p353(2013-11-22修订版43784)[i686-Linux]
这是有关此主题的好文章:http://37signals.com/svn/posts/3091-pssst-your-rails-rails-rails-application-has-a-a-a-a-a-secret-secret-secretto-tell to-tell - 你
好吧,您确定Redis和ActiveSupport ::通知具有相同的订阅方法吗?
所以这可能是导致铁轨问题的原因:
def close
@response.commit!
@closed = true
end
def write(string)
raise IOError, "closed stream" if closed?
@response.commit!
@buf.push string
end
您要确保流关闭。写入打电话时,它会通过IOERROR if closed?
进行,您要确保发生这种情况。我不是100%确定一切都在发生的,但这似乎是最有可能的罪魁祸首。
所以我回去看一些事情:
在响应的初始化中,我们有:
self.body, self.header, self.status = body, header, status
这是body=
def body=(body)
@blank = true if body == EMPTY
if body.respond_to?(:to_path)
@stream = body
else
synchronize do
@stream = build_buffer self, munge_body_object(body)
end
end
end
将@stream
=设置为新的Buffer
def build_buffer(response, body)
Buffer.new response, body
end
所以我认为您的罪魁祸首实际上是您确保response.stream.close
。现在,我不确定在写作之前如何调用它。您是先做REDIS,然后测试实时写作,并且它们是否使用相同的响应?如果是这样,您可能会设置要关闭的响应,然后尝试使用它来编写,这将通过ioError。