I've been looking for ways of triggering server-side events with ActionController::Live without the use of polling. It seems like the only documented pub/sub solution for Live is to use Redis, but I'd really like to just use the stack I currently have. I came across ActiveSupport::Notifications, which seems to do just what I want.
However, when I use it nearly in-place of Redis, Live throws an IOError and the stream gets closed. I don't see any valid reason as to why this would happen.
For example, this supposedly works:
def stream
response.headers['Content-Type'] = 'text/event-stream'
redis = Redis.new
redis.subscribe('namespaced:stream') do |on|
response.stream.write "hello world\n"
end
rescue IOError
# Client Disconnected
ensure
response.stream.close
end
But when I try this I get an IO Error:
def stream
response.headers['Content-Type'] = 'text/event-stream'
ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
response.stream.write "hello world\n"
end
rescue IOError
# Client Disconnected
ensure
response.stream.close
end
I'm really at a loss as to why this is happening. Nothing in the server log indicates an actual problem, and the notification subscription works otherwise; I can tell because even if I get an IO Error I can still get the subscription to puts a string to the console when a "process_action.action_controller" notification occurs.
When the notification doesn't occur, the connection works just fine but as soon as there is a notification(which I'd think should just write "hello world" to the stream), I get that silly IO Error.
By the way, I do plan on instrumenting my own notifications; just testing with existing notifications is easier.
Oh, and here's a copy of what happens in the terminal when I visit the route that uses the stream controller method:
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'
I apologize if I am getting any terminology wrong, for I am new to SSEs and Rails in general, so I would greatly appreciate any help with this.
EDIT: In case you need to know, I am using the following:
- Rails 4.0.2
- Ruby 2.0.0p353 (2013-11-22 revision 43784) [i686-linux]