Rails 中的 Server-sent 个事件未异步传送
Server-sent events in Rails not delivered asynchronously
我正在尝试编写一个 API,它使用 Rails 中的 ActionController::Live::SSE
传递 server-sent 事件 6. 为了理解如何最好地编写测试,我基本上是从 copying the trivial example seen here 开始的:
my_controller.rb
:
class MyController < ApplicationController
include ActionController::Live
def capture
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream)
3.times do
sse.write({message: "Awaiting confirmation ..."})
sleep 2
end
fake_response = { #The response as hash.
"annotation_id"=>nil,
"domain"=>"some.random.com",
"id"=>2216354,
"path"=>"/flummoxer/",
"protocol"=>"https",
}
sse.write(fake_response, event: 'successful capture')
rescue => e
sse.write(e.message, event: 'something broke: ')
ensure
response.stream.close
end
end
当我向此端点发送 curl 请求(无论是 POST 还是 GET)时,响应全部到达一个块,而不是作为单独的响应:
$ curl -i -X GET -H "Content-Type: application/json" -d '{"url": "https://some.random.com/flummoxer"}' http://localhost:3000/capture
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
ETag: W/"a24048695d2feca40232467f0fbb410a"
X-Request-Id: 648a5229-a43d-40d3-82fd-1c4ea6fe19cc
X-Runtime: 24.082528
Transfer-Encoding: chunked
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
在我的测试中,尝试解析来自我的服务器的响应失败这一事实更容易看出这一点:
MultiJson::ParseError: 783: unexpected token at 'data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
'
我的服务器是 Puma,所以 。
我做错了什么?如果您需要,我会提供可能有用的任何其他信息。
更新: 建议将 -N
和 Accept:text/event-stream
header 添加到请求中。这样做不会改变我上面描述的行为——在对 response.stream.close
的调用被触发之前不会发送对请求的响应。
更新 2:我还尝试破解 SSE#write
方法以在 Mutex::ConditionVariable
上调用 broadcast()
以强制发送消息。从它立即发送数据的意义上说,这是可行的,但 curl 请求的副作用是认为流已关闭,因此不会发送更多消息,这不是流。
更新 3:我还修改了 development.rb
以包含 config.allow_concurrency = true
,如 here 所示。上述行为没有变化。
我 运行 遇到了与基本 'out the book' Rails 5 SSE 应用程序类似的问题。问题原来是导致流缓冲的机架更新。更多信息在这里 https://github.com/rack/rack/issues/1619 并通过包含
修复
config.middleware.delete Rack::ETag
在config/application.rb
我正在尝试编写一个 API,它使用 Rails 中的 ActionController::Live::SSE
传递 server-sent 事件 6. 为了理解如何最好地编写测试,我基本上是从 copying the trivial example seen here 开始的:
my_controller.rb
:
class MyController < ApplicationController
include ActionController::Live
def capture
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream)
3.times do
sse.write({message: "Awaiting confirmation ..."})
sleep 2
end
fake_response = { #The response as hash.
"annotation_id"=>nil,
"domain"=>"some.random.com",
"id"=>2216354,
"path"=>"/flummoxer/",
"protocol"=>"https",
}
sse.write(fake_response, event: 'successful capture')
rescue => e
sse.write(e.message, event: 'something broke: ')
ensure
response.stream.close
end
end
当我向此端点发送 curl 请求(无论是 POST 还是 GET)时,响应全部到达一个块,而不是作为单独的响应:
$ curl -i -X GET -H "Content-Type: application/json" -d '{"url": "https://some.random.com/flummoxer"}' http://localhost:3000/capture
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
ETag: W/"a24048695d2feca40232467f0fbb410a"
X-Request-Id: 648a5229-a43d-40d3-82fd-1c4ea6fe19cc
X-Runtime: 24.082528
Transfer-Encoding: chunked
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
在我的测试中,尝试解析来自我的服务器的响应失败这一事实更容易看出这一点:
MultiJson::ParseError: 783: unexpected token at 'data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
'
我的服务器是 Puma,所以
我做错了什么?如果您需要,我会提供可能有用的任何其他信息。
更新:-N
和 Accept:text/event-stream
header 添加到请求中。这样做不会改变我上面描述的行为——在对 response.stream.close
的调用被触发之前不会发送对请求的响应。
更新 2:我还尝试破解 SSE#write
方法以在 Mutex::ConditionVariable
上调用 broadcast()
以强制发送消息。从它立即发送数据的意义上说,这是可行的,但 curl 请求的副作用是认为流已关闭,因此不会发送更多消息,这不是流。
更新 3:我还修改了 development.rb
以包含 config.allow_concurrency = true
,如 here 所示。上述行为没有变化。
我 运行 遇到了与基本 'out the book' Rails 5 SSE 应用程序类似的问题。问题原来是导致流缓冲的机架更新。更多信息在这里 https://github.com/rack/rack/issues/1619 并通过包含
修复config.middleware.delete Rack::ETag
在config/application.rb