Search code examples
ruby-on-rails-4nginxstreamingserver-sent-eventspuma

Writing to closed stream on EC2 instance does not result in IOError


My application has a streaming endpoint where I'm using ActionController::Live. In my controller action, all my code that writes to the stream is wrapped in begin rescue ensure blocks so that I can clean up the resources I'm using.

When I close the the browser window that is connected to the streaming endpoint on my local machine, everything is correctly cleaned up.

When I do the same with my application running behind ELB with an nginx reverse proxying to my puma server, the controller action doesn't indicate that it has recieved an error, in my nginx error log I'm getting

*11820 connect() to unix:///var/run/puma/my_app.sock failed (11: Resource temporarily unavailable) while connecting to upstream

For reference, here is what my controller action looks like: https://gist.github.com/teddythetwig/b5c6396993030a18aac5


Solution

  • I ended up giving up on ActionController::Live and just using the excellent Tubesock library. Even switching though, I had to follow a few very poorly documented steps.

    Firstly, you have to enable HTTP v1.1 in your nginx configuration file, because v1.0 doesn't support chunked-encoding.

    proxy_http_version 1.1;

    and you also have to set the Connection header to an empty string

    proxy_set_header Connection "";

    Next you have to enable proxy protocol on your ELB instance, which imho, is kind of a pain in the ass. Here are some instructions from Amazon.

    The part where I finally quit with AC::Live and switched to Websockets was with playing around with the keepalive time on nginx, and the idle timeout on ELB.

    Honestly, if you are trying to keep a connection this way, I would suggest just switching to Websockets. ActionController::Live just isn't the best way to accomplish what we are trying to do. It's great for streaming data in a dumb fashion(controller actions that will terminate after doing x,y, and z).