aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
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
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')
-rw-r--r--actionpack/lib/action_controller/metal/live.rb28
-rw-r--r--actionpack/lib/action_controller/test_case.rb12
2 files changed, 36 insertions, 4 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
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index c4c825ba6b..ca1ecc43a1 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -517,8 +517,8 @@ module ActionController
end
def setup_controller_request_and_response
- @request = TestRequest.new
- @response = TestResponse.new
+ @request = build_request
+ @response = build_response
@response.request = @request
@controller = nil unless defined? @controller
@@ -539,6 +539,14 @@ module ActionController
end
end
+ def build_request
+ TestRequest.new
+ end
+
+ def build_response
+ TestResponse.new
+ end
+
included do
include ActionController::TemplateAssertions
include ActionDispatch::Assertions