3

I am trying to write data to the stream at a set interval of time.

class StreamController < ApplicationController
  include ActionController::Live

  def stream
    response.headers['Content-Type'] = 'text/event-stream'
    5.times do
      response.stream.write "data: hello world\n\n"
      sleep 1
    end
  ensure
    response.stream.close
  end
end

But when I send a get request (using curl) to the /stream endpoint I get: "data: hello world\n\n" 5 times all at once after 5 seconds, instead of receiving "data: hello world\n\n" once per second. I am using the default puma webserver that comes with rails 7.0.4. My guess is that it buffers the response then sends it when calling response.stream.close.

I tried adding options = { flush_headers: true } to the puma config file but it didn't help.

  • You're probably hitting https://github.com/puma/puma/issues/3000 - says Sinatra but should Rails should suffer from the same issue as well. – avl Feb 12 '23 at 15:44

1 Answers1

2

rack and puma have been figuring this out and fixing bugs for so long. Officially, you need rack v3 and puma v6, but rails 7 doesn't support rack v3.

As far as I can tell the last hickup is Rack::ETag middleware, which you can delete config.middleware.delete Rack::ETag. But you probably need it, so a workaround for now:

class StreamController < ApplicationController
  include ActionController::Live

  def stream
    response.headers["Content-Type"] = "text/event-stream"

    # this bypasses etag calculation and magic happens
    response.headers["Last-Modified"] = Time.now.httpdate

    5.times {
      response.stream.write "hello world\n"
      sleep 1
    }
  ensure
    response.stream.close
  end
end

If you see ETag: W/"53827b3eddcd709c853e748ffd5314fb", you're doing it wrong:

$ curl -i http://localhost:3000/stream/stream
HTTP/1.1 200 OK
Content-Type: text/event-stream
Last-Modified: Tue, 22 Aug 2023 10:29:34 GMT
Cache-Control: no-cache
X-Request-Id: 3dbb7f14-e167-4b5c-9cea-27c4ec131f24
X-Runtime: 0.094270
Server-Timing: start_processing.action_controller;dur=0.16
Transfer-Encoding: chunked

hello world
hello world
hello world
hello world
hello world

you can't tell, but it was streaming :) puma v6.3.1 rack v2.2.7

https://github.com/rack/rack/issues/1619

Alex
  • 16,409
  • 6
  • 40
  • 56