Flushing output stream(ob_flush() equivalent)

I’m trying to find a way to flush the output buffer. I have done this before in java and php but cannot find a method in ruby/rails? Is this possible?

-m

Rails doesn't do streaming for regular requests, but it does provide an API for streaming responses.

http://datanoise.com/articles/2006/03/17/rails-and-response-streaming

Thanks for the input. I’ve tried send_data previously and it does not provide the function I need. I’ve also tried using $stdout.flush and it doesn’t seem to affect anything. Any other suggestions welcomed.

-m

Looking through the changelog I found this:

  • render_text now accepts a block for deferred rendering. Useful for
    streaming large files, displaying a “please wait” message during a complex search, etc. Streaming

example:

 render_text do |response|
   File.open(path, 'rb') do |file|
     while buf = file.read(1024)
       print buf
     end
   end
 end

[Jeremy Kemper]

Yet when I try this it does not work. I wonder if this has been removed in later releases?

-m

render :text => lambda { |response, out|      File.open(path, 'rb') do |file|        while buf = file.read(1024)          out.print buf        end      end }

Thanks Kent, but I’ve tried that and it doesn’t provide what I want. If I do :

render :text => lambda { |response, out|  
  out << "Sleeping"
  sleep(10)
  out << "Waking Up"   
}

What I’m expecting here is to see “Sleeping” then after the sleep duration, “Waking Up”. However it does not stream the response, it will process the whole block and then send the response. No different then how it normally renders.

You should use out.flush method

class TestController < ApplicationController   def index     render :text => lambda { |resp, out|       out.puts 'start'       out.flush       10.times do         out.puts '.'         out.flush         sleep 1       end       out.puts 'done'     }   end end

Note it works only with fastcgi setup. It doesn't work with webrick.

I’ve tried of all this and I’m using lighttpd and still it does not flush the output buffer. I’ve tested this in production and development mode, I even tried mongrel just for kicks. Tested it on more then one machine with the help of a coworker here at work. I am not sure if maybe at work our configuration is somehow preventing this to function, but we are running a standard setup and I really don’t see how that can be. In the meantime I will have some of my other friends try this on their setups and see if they can get it to work. Any other suggestions would be truly appreciated.

regards, m

If you are using a browser to test it, you won’t see the difference. Use curl for that. In my example,

$ curl http://localhost:3000/test

You will see the output printed after each flush method is being called.

I’ve been using mozilla and lynx to test and now I’ve just used curl and the same thing happens. It’s not streaming the output. I am wondering if its something within my setup thats preventing me from getting this to work. My co-worker has tried the same code on his development system and it doesn’t work for him either. I am wondering if I can replicate your rails/server setup if I could get it to work.

-m

The saga continues - I refuse to give up. I’ve determined that its not a server issue at this point, I’ve used lighttpd, apache with fcgid, mongrel and no luck still. Me and a coworker are working on a workaround for this since output streaming seems like a pipe dream at this point. In the meantime it would be nice to get the specs of a system setup that is known to work with streaming so I can implement it and see if I have better results. In the meanwhile I have a $20 prize over at Guruza http://guruza.com/question/358/reward-20.00 to anyone who can help answer this question.

Miguel,

I'm using lighttpd with fastcgi and it streams just fine. With my example if I use curl to query my action URL, I can see the output after each our.flush invocation.

Oh, I missed this, sorry but you can't stream from rails in Mongrel at the least, probably in none of them. Mostly because Rails does some buffering and Mongrel does some buffering and Rails likes to change its mind mid-stream.

If there's a particular action that needs streaming and you can break it out of rails then it is possible to write Mongrel handler that streams fairly quickly. In fact Mongrel does this when sending a file.

Another option, is if you can pack up what Rails is supposed to send in a streaming fashion, then you can write a simple Mongrel handler that does the heavy lifting of streaming it out to the user.

Otherwise, having Rails do the actual streaming will stop the other clients since while Rails is streaming you'll be locked.

Go ahead and give the $20 to a charity. :slight_smile:

Rails calls output.write on the IO the dispatcher hands it; Mongrel hands Rails a StringIO. The only exception I recall is that send_file used to call output.syswrite, if available, to bypass Ruby buffered IO.

jeremy

No, send_file uses output.write method. If Rails is deployed in the fastcgi environment, your output object is FCGI::Stream which doesn't provide sysread/syswrite methods. All buffering in this case is provided by fastcgi library and 'flush' method is supported.