Anyone that has written a little PHP knows what the
flush() family of functions do. The ideal usage scenario for using chunked transfer is when we have something costly to render e.g. the first three most recent articles on a blog. Why ? one might ask.
Is rather simple: in a normal request where the server responds with a
Content-Length header the browser will wait until the whole page comes down the wire then it goes loading the assets et al.
Transfer-Encoding: chunked header, the server will send chunks of the rendered page back to the browser so in the case of Rails, it starts with the layout and sends out the
<head> part including assets like js and css.
It's clear how this helps the rendering of the page on the client side : get the first chunk containing the
<head> with assets, immediately start loading the assets while waiting for the rest of the response. Of course, browsers nowadays include lots of micro-optimizations that might already do something similar but still this remains a good practice.
Implementation wise, you just need to add to your controller methods something like :
class YourController < ApplicationController def index @articles = Article.most_recent render stream: true end # other controller logic end
The latest version of Unicorn (4.x) comes by default with support for chunked response. You can always add to your
unicorn_config.rb something like:
# :tcp_nopush This prevents partial TCP frames from being sent out # :tcp_nodelay Disables Nagle’s algorithm on TCP sockets if true. port = ENV["PORT"].to_i || 3000 # the ENV["PORT"] is a Heroku environment variable listen port, tcp_nopush: false, tcp_nodelay: true
We also have some quirks when using streaming in Rails because of the inversion of template rendering order:
When streaming, rendering happens top-down instead of inside-out. Rails starts with the layout, and the template is rendered later, when its yield is reached .
provide instead of
content_for when you have multiple calls to
content_for otherwise it will break the purpose of streaming and/or it will concatenate the values from
There's also a “small” issue with NewRelic agent and Heroku: you need to disable browser instrumentation or else you'll get a blank page, thankfully the fix is rather trivial:
ActionController::Live that can be used to create a simple Rails 4 chat application.