Simple Rails 4 ActionController::Live example not working with Apache + Passenger
Asked Answered
I

3

6

I am attempting to get ready to move our environment to Rails 4 and working through all the issues. Regretfully we are currently on Centos 5.5 so there were some hurdles to jump through just to get Rails up and running. This included installing python 2.6 and node.js in order to get extjs working.

And now I am stuck. With a fresh rails 4.0.2 app I have simple ActionController::Live example working fine in development with Puma. But in production with Apache + Passenger it simply doesn't send the data back to the browser (Firefox)

production.rb has

config.allow_concurrency = true

Here is the HTML/JS in index.html.

<script>
jQuery(document).ready(function(){
   var source = new EventSource("/feed");
   source.addEventListener('update', function(e){
     console.log(e.data);
   });

});
</script>

Here is the controller:

class LiveController < ApplicationController
  include ActionController::Live
  respond_to :html
  def feed
    response.headers['Content-Type']      = 'text/event-stream'
    response.headers['X-Accel-Buffering'] = 'no'

    while true do 
      response.stream.write "id: 0\n"
      response.stream.write "event: update\n"
      data = {time: Time.now.to_s}.to_json
      response.stream.write "data: #{data}\n\n"
      sleep 2
    end
  end
end

I can see the request go out to the server in Firebug notice the spinner on /feed :

Firebug Request notice the spinner

Apache/Passenger Config has this:

LoadModule passenger_module /usr/local/ordernow/lib/ruby/gems/2.0.0/gems/passenger-4.0.27/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/ordernow/lib/ruby/gems/2.0.0/gems/passenger-4.0.27
PassengerDefaultRuby /usr/local/ordernow/bin/ruby
RailsAppSpawnerIdleTime 0
PassengerMinInstances 1

The Apache logs don't show anything. Like it never connects to the server. Another weird thing is that curl from the command line works:

     curl -k -i -H "Accept: text/event-stream" https://10.47.47.44:8446/feed
HTTP/1.1 200 OK
Date: Thu, 27 Mar 2014 16:52:52 GMT
Server: Apache/2.2.20 (Unix) mod_ssl/2.2.20 OpenSSL/1.0.0e Phusion_Passenger/4.0.27
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
X-Accel-Buffering: no
Cache-Control: no-cache
X-Request-Id: 46fca6bb-4c6a-49f4-b0d6-2cbc5f0a63a5
X-Runtime: 0.002065
X-Powered-By: Phusion Passenger 4.0.27
Set-Cookie: request_method=GET; path=/
Status: 200 OK
Vary: Accept-Encoding
Transfer-Encoding: chunked
Content-Type: text/event-stream

id: 0
event: update
data: {"time":"2014-03-27 10:52:52 -0600"}

id: 0
event: update
data: {"time":"2014-03-27 10:52:54 -0600"}

I figure it must be something in Apache , but I am not sure.

Idiopathy answered 17/3, 2014 at 3:26 Comment(7)
have you checked the apache log files?Permanence
interesting. Nothing in the access logs. So it isn't even reaching Apache? Strangely it works from curlIdiopathy
maybe, it works from curl command line though. So what firewall setting would be triggering it?Idiopathy
If I close the response stream then I get the data. But only at the end. So it doesn't appear to be firewall. It appears to be buffering.Idiopathy
looks like it might be a clientside issue then. Are you using exactly the same version of the browser? could you be running into a cross site javascript request maybe?Permanence
It works locally just fine, but that is using puma. I'll get apache passenger setup on my mac and see if the problem happens there.Idiopathy
thanks @Permanence for simply letting me know I wasn't alone. I finally figured it out. mod_deflate was on for all requests which interfered with non-buffered responses.Idiopathy
I
5

Okay I finally figured this out by a pile of googling that lead me to an indication that mod_deflate ( used for compressing responses to the browser ) will interfere with non-buffered responses like text/event-stream.

Looking at my httpd.conf I found this:

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpg|png|ico|zip|gz)$ no-gzip

# Restrict compression to these MIME types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css

# Level of compression (Highest 9 - Lowest 1)
DeflateCompressionLevel 9

SetOutputFilter DEFLATE turns on compression for all responses making the rest of the AddOutputFilterByType directives unnecessary. This was obviously a bug in the httpd.conf . I removed this line, and verified that compression was still working for html pages.

And now everything works great! As well as the dashing dashboard tool that I was trying to get going in the first place.

Idiopathy answered 29/3, 2014 at 16:36 Comment(0)
W
2

We've experienced some similar issue when we wanted to push some notifications with the Rails Action::LiveController as the feature was released with Rails 4.0 - in development with Puma everything works fine, but in production the streams we're not closed. This was resulting in a steadily increasing number of processes. Back then we came back to a different solution.

But just today I started some research (very interesting SO answer by one of the Passenger authors: https://stackoverflow.com/a/4113570) on this topic again and ended up here - right after I've read that Phusion Passenger supports Concurrency and Multithreading only with the Enterprise version (Phusion Passenger Enterprise Features).

Is it possible that a production environment with an Apache2 Web Server integration Phusion Passenger Open Source Edition isn't suitable for Rails Live Streaming?

Honestly, I have no idea - but wanted to let you know of my thoughts on this.

Wurth answered 28/3, 2014 at 17:13 Comment(1)
I got it working with the open source version of passenger. Problem was mod_deflate, I added an answer below. Thanks for chiming in.Idiopathy
I
0

To prevent the Server (nginx to be honest) from deflating in specific cases, we set

response.headers['Cache-Control'] = 'no-transform, no-cache, private'

Maybe one of these is enough ;)

Rails 5

Invisible answered 12/5, 2022 at 15:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.