views:

783

answers:

4

I'm experiencing something that I can't explain with Rails 2.3.2. I've created a new app, with one controller and one action to try narrowing this down. My entire controller is as follows.

class LinesController < ApplicationController
  def show
    respond_to do |format|
      format.html { render :text => proc {|response, output|
          10.times do |i|
            output.write("This is line #{i}\n")
            output.flush
          end
        }
      }
    end
  end
end

When I run this under Rails 2.2.2 I see the following response.

$ curl http://localhost:3002/lines
This is line 0
This is line 1
This is line 2
This is line 3
This is line 4
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9

However, when I run this under Rails 2.3.2, I get this instead.

$ curl http://localhost:3002/lines
curl: (18) transfer closed with outstanding read data remaining

If I hit this with a browser I see only the first line.

This is line 0

Note that my example code is directly out of the Rails documentation for render, except that I reduced the number of lines from 10 million to 10.

I suspect that the answer lies somewhere in the flush() method, but I'm currently stuck trying to dig an explanation out of the source code.

+3  A: 

I believe this bug was resolved on 2-3-stable by commit bc2c4a45959be21e6314fba7876b32c1f04cd08a. Check out the accompanying ticket. You can either wait for 2.3.3 (not that far off now), or freeze the current 2-3-stable from git:

git clone git://github.com/rails/rails.git vendor/rails
cd vendor/rails
git checkout origin/2-3-stable
rm -rf .git
Yehuda Katz
A good thought, but sadly not the answer. I saw that bug referenced a few times when researching this, but it seems to have more to do with keeping model objects in memory than properly flushing the output buffer.
jdl
I should mention that I did follow your steps to double-check, and I get the same thing that I saw on 2.3.2 as well as edge.
jdl
Would you mind opening a ticket about this on the Lighthouse tracker. I'll make sure it gets looked at.
Yehuda Katz
Thank you. I added the ticket here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2893-rails-23x-render-text-proc-problems-with-output-buffer
jdl
Looks like 2.3.4 will have the fix for this. If I'm reading the ticket correctly, the call to .flush() will no longer be needed.
jdl
A: 

I met the same problem, the stack trace showed that output.flush does not work.

The error message is like:Read error: #<NoMethodError: undefined method `flush' for #<ActionController::Response:0xb74c1050>>
A: 

Hi,

I'm using rails 2.3.4. When I try to call the flush method, I have the deprecation warning as discussed here. However, when I drop the flush call, the data is not really streamed : it is first generated on the server side, then transmitted in one block when generation is finished.

I cannot find much information about this, except "flush is called automatically". I'd like to have more details about this : when is it called ? Is it server-dependent (tried with thin, mongrel and webrick) ? Do we have a way to configure the "buffer size before flush" ?

Thanks in advance,

Nicolas

A: 

We had a similar (to Nicolas') problem on Rails 2.3.2, the data being buffered somewhere before it was sent to the user. We traced the problem to mongrel in our QA environment, but the streaming worked perfectly in development env (without flushing).

The problem was that script/server in dev env would use rack as the engine with a mongrel adapter on top, which works fine. However, in QA we were using mongrel_clusterwhich uses the older implementation of mongrel with only a RailsAdapter (also used in Rails 2.2 and older). Switching mongrel_cluster to Passenger should do the trick, or alternatively implementing the clustering manually for the rack-based mongrel.

Tommi R.