aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/metal/live.rb
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2012-07-29 19:23:19 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2012-07-29 21:43:05 -0700
commit38cfbb8aa7e4aa4d9467e1706c50c3573cc714aa (patch)
treeb664221b29148aad84f38a1ffddc13542728a7e4 /actionpack/lib/action_controller/metal/live.rb
parent06c9e176ca1b74e99bc258295bfbd8d2f2f33563 (diff)
downloadrails-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.rb28
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