sinatra 1.3 streaming: redirecting processes

Process Management

In ruby, when you want to run and redirect process output, you have many options.
Here are some:

    (1) result = `command`
    # stdout, stderr if redirected. Buffered until completion.

    (2) pipe = IO.popen("command", "r")
    # stdout, stderr if redirected. Get chunks while running.

    (3) Open3.popen3("command")
    # all 3 streams (in, out, err). Get chunks while running.

Streaming with Sinatra

From 1.3.0, sinatra supports streaming. It gets really impressive on an evented server such as Thin, considering that such behavior was reserved either to dedicated frameworks such as cramp and goliath, or even nodejs.

Spawning and Streaming

A typical CI server would spawn processes and listen in on their output. Lets see how this might happen easily.

We'll pick option (2) for redirecting.

    require 'rubygems'
    require 'sinatra'

    cmd = 'ruby bomb.rb'

    get '/' do
      stream do |outp|
        IO.popen(cmd, 'r') do |io|
          while line=io.gets
            puts line
            outp << line

And here is our bomb.rb process.

    $stdout.sync = true
    5.times { puts "tick."; sleep 1; puts "tock."; sleep 1}
    puts 'KABOOM!'

Its important to instruct ruby to flush content immediately with $stdout.sync = true otherwise, we would wait a long time to get a non-streaming content. Try it out.

Easily enough, you can open up several browsers to esperience how great this is. If you get a 'stuck' request, make sure to append some garbage to your url such as http://localhost:4567?r=123. I think this has to do with browser cache mechanisms.