Sinatra streaming with Puma?
Asked Answered
T

1

9

I'm trying to leverage Server-Sent Events in my application. I am using Sinatra and the sinatra-sse gem. This gem wraps the Sinatra stream :keep_alive call.

When running my application on Thin, I have absolutely no problems, and my event stream works as expected. However, when I switched my application to run with Puma everything works, except my sse_stream does absolutely nothing! It just returns a blank page.

My stream is set up like so

get "/logstream/:server" do
    if rbcserver = MyApp.servers[params[:server]]
        sse_stream do |stream|     
            rbcserver.add_web_logger(stream)
            stream.callback { rbcserver.remove_web_logger(stream) }
        end
    else
        error 404
    end
end

I'm starting Thin like so:

@@puma_instance = Puma::Server.new MyApp::WebUI
@@puma_instance.add_tcp_listener ip, port
@@puma_instance.run

Any idea what's going on? Any help would be appreciated.

EDIT: some more info This is what cURL gives when running on Puma

$ curl -L -b cookies.txt -c cookies.txt -i http://localhost:9001/logstream/myserver    
HTTP/1.1 200 OK
Content-Type: text/event-stream;charset=utf-8
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked

$

Whereas this is what happens on Thin

$ curl -L -b cookies.txt -c cookies.txt -i http://localhost:9001/logstream/myserver                                        
HTTP/1.1 200 OK
Content-Type: text/event-stream;charset=utf-8
X-Content-Type-Options: nosniff
Connection: close
Server: thin 1.5.1 codename Straight Razor

event: <event name>
data: <my data>

event: <event name>
data: <my data>

<continues as more data comes in>

EDIT: I should add that my application uses EventMachine at its core, so sinatra_sse's coupling to EM is most likely not an issue.

Tavey answered 1/4, 2013 at 18:32 Comment(0)
B
3

I believe the issue revolves around sinatra-sse's explicit use of the EventMachine library, which it does not list as a dependency. It does, however, list Thin in its Gemfile and EventMachine is a core dependency of Thin.

Puma's concurrency model is quite different. In fact, you'll find the following statement right at the top of the project's README:

Puma still improves MRI's throughput by allowing blocking IO to be run concurrently (EventMachine-based servers such as Thin turn off this ability, requiring you to use special libraries).

EDIT

If you're interested in learning more about Rack, Rails, Puma, and SSE, you might enjoy this great blog post by Aaron Patterson, a Ruby/Rails core member and all-around swell guy.

Beamy answered 10/4, 2013 at 9:53 Comment(3)
Well, my application uses EventMachine as well, so I don't think this is caused by EventMachine not running. Also that particular line you linked seems to be used only to keep the connection open for when there's no data sent. My application sends a generous amount of data regularly, so I don't think that has anything to do with it :/Tavey
@IlyaO. Just edited my answer with a link to a Puma github issue outlining the roadblocks for a Puma implementation of async.callback.Beamy
Just gave the ticket a bump. I'll give you the bounty if nobody else has anything to add.Tavey

© 2022 - 2024 — McMap. All rights reserved.