diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2012-07-29 19:23:19 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2012-07-29 21:43:05 -0700 |
commit | 38cfbb8aa7e4aa4d9467e1706c50c3573cc714aa (patch) | |
tree | b664221b29148aad84f38a1ffddc13542728a7e4 /actionpack/lib/action_controller/metal/live.rb | |
parent | 06c9e176ca1b74e99bc258295bfbd8d2f2f33563 (diff) | |
download | rails-38cfbb8aa7e4aa4d9467e1706c50c3573cc714aa.tar.gz rails-38cfbb8aa7e4aa4d9467e1706c50c3573cc714aa.tar.bz2 rails-38cfbb8aa7e4aa4d9467e1706c50c3573cc714aa.zip |
Controller actions are processed in a separate thread for live
responses.
Processing controller actions in a separate thread allows us to work
around the rack api - we can allow the user to set status and headers,
then block until the first bytes are written. As soon as the first
bytes are written, the main thread can return the status, headers, and
(essentially) a queue for the body.
Diffstat (limited to 'actionpack/lib/action_controller/metal/live.rb')
-rw-r--r-- | actionpack/lib/action_controller/metal/live.rb | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index efeeefda9d..48818cb8e4 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -6,8 +6,7 @@ module ActionController class Response < ActionDispatch::Response class Buffer < ActionDispatch::Response::Buffer # :nodoc: def initialize(response) - @response = response - @buf = Queue.new + super(response, Queue.new) end def write(string) @@ -59,5 +58,30 @@ module ActionController buf end end + + def process(name) + t1 = Thread.current + locals = t1.keys.map { |key| [key, t1[key]] } + + # This processes the action in a child thread. It lets us return the + # response code and headers back up the rack stack, and still process + # the body in parallel with sending data to the client + Thread.new { + t2 = Thread.current + t2.abort_on_exception = true + + # Since we're processing the view in a different thread, copy the + # thread locals from the main thread to the child thread. :'( + locals.each { |k,v| t2[k] = v } + + begin + super(name) + ensure + @_response.commit! + end + } + + @_response.await_commit + end end end |