HTTP progressive output / server push

Is it possible to override the standard Rails rendering infrastructure
for a single controller action, in such a way that I can generated
“progressive” HTTP output? That is, the browser can display text as it
is generated, rather than Rails buffering the whole page and sending
it once at completion?

Here’s a trivial example, written as a CGI:


#!/usr/bin/ruby -w
$stdout.sync = true
puts “Content-Type: text/html”
puts
puts “”, " " * 256
puts “”
(1…10).each do |i|
puts “

#{i}


sleep 1
end
puts “”

If you stick this in /cgi-bin/ and point a browser at it then you can
see the numbers going down the screen one per second. (The real-world
application I have is for displaying progress during a long-running
operation, such as uploading firmware to a router). I can’t write the
above in Rails currently.

And here’s another example, which I found on the web, using x-mixed-
replace:


#!/bin/sh
#echo “HTTP/1.0 200”
echo “Content-type: multipart/x-mixed-replace;boundary=—
ThisRandomString—”
echo “”
echo “—ThisRandomString—”
while true
do
echo “Content-type: text/html”
echo “”
echo “

Processes on this machine updated every 5 seconds


echo "time: "
date
echo “


echo “”
ps -el
echo “—ThisRandomString—”
sleep 5
done

Now, clearly I can run these as CGIs, but then I would lose Rails’
lovely routing and parameter handling, and its integration with
ActiveRecord with persistent database connections.

Basically I want something like this:

def myaction

browser.puts “string1”

browser.puts “string2”

render :none=>true
end

For me the key issue is: do the underlying web servers that Rails runs
under, such as webrick and mongrel, allow the response to be sent in
parts? Is there some IO-like object hanging around that I could call
‘puts’ or ‘write’ on to send data directly back to the browser?

There are other ways to achieve what I want, but they add a lot of
complexity and are less real-time. For example, the browser can be set
to poll for status every 5 seconds, but then one Rails process is
doing work and has to publish its progress to some object, which
another Rails process checks for data.

Other ideas are welcomed.

Regards,

Brian.

Should be possible with a custom mongrel handler.

On 8/7/07, candlerb [email protected] wrote:

#!/usr/bin/ruby -w


echo “

Processes on this machine updated every 5 seconds


Now, clearly I can run these as CGIs, but then I would lose Rails’

to poll for status every 5 seconds, but then one Rails process is


Cheers!

Should be possible with a custom mongrel handler.

Thank you, that gave me some useful keywords to put into Google :slight_smile:

But if I understand correctly, I would still lose all of Rails routing

  • I’d just get a raw HTTP request object from Mongrel?

Regards, Brian.