Rails Streaming Not Streaming

Rails streaming: render stream: true not working

I tried the demo repo you mentioned and the behaviour is as expected. In the example you show it will stop streaming the template, then wait for it to be fully rendered after 5 sec and send the rest. If you use curl:

# curl -i http://localhost:3000

HTTP/1.1 200 OK
Date: Thu, 21 Apr 2016 17:29:00 GMT
Connection: close
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
X-UA-Compatible: IE=Edge
X-Runtime: 0.018132

<!DOCTYPE html>
<html>
<head>
<title>StreamingTest</title>
<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
<script src="/javascripts/application.js" type="text/javascript"></script>
<meta content="authenticity_token" name="csrf-param" />

Then it waits for 5 seconds for the template to finish its rendering and then sends it.

  ...
<p>
I should get streamed...
</p>
</body></html>

That's what's supposed to happen. It will not send a part of the partial every 0,5 seconds.

The main goal of streaming with templates is for the browser to receive the headers before the rest of the content so that it makes it possible to save some time in loading assets. As stated in the docs.

Streaming inverts the rendering flow by rendering the layout first and streaming each part of the layout as they are processed. This allows the header of the HTML (which is usually in the layout) to be streamed back to client very quickly, allowing JavaScripts and stylesheets to be loaded earlier than usual.

It's not going to send the partial unless it's been fully rendered.

However, to show you how to get the kind of behaviour you're expecting you could change the body of application.html.slim layout like this:

  body
= yield
= render 'application/other'

And create a partial named _other.html.erb with the following content

<% sleep 1 %>
<p>Me too!</p>

And now you'll see in curl that it renders the beginning of the layout, waits for the rendering to be finished on index.html.erb, sends it and shows up in curl and then waits for the _other.html.erb partial to be finished rendering to end the request body. Voilà.

You could also directly feed the request body, to send content every few milliseconds, you can do the following:

def index
headers['Cache-Control'] = 'no-cache'
self.response_body = Enumerator.new do |yielder|
10.times do
yielder << "I should be streamed...\n"
sleep 0.3
end
end
end

This is however not meant to send html, although you could by using render_to_string but then you'll have to modify quite a lot in your code.

Note that all this is Rails 3.x, for 4.x you'll have to use ActionController::Live. In the case of ActionController::Live, there are examples on how to listen to the server sent events in js to render client side such as this mini-chat.

Streaming with ActionController::Live not working in production

I had a similar issue with a recent project. I found it was my nginx config.

Add the following to the location section:

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;

This information was obtained from the following Stack Overflow discussion:

EventSource / Server-Sent Events through Nginx

Hope this helps.



Related Topics



Leave a reply



Submit