diff options
author | Matthew Draper <matthew@trebex.net> | 2016-02-07 08:24:57 +1030 |
---|---|---|
committer | Matthew Draper <matthew@trebex.net> | 2016-02-07 08:32:27 +1030 |
commit | 3e4a69e52d8c8f0335e0ddbb46fe21009b962334 (patch) | |
tree | 172481e3ea5e3ed7496ff2541a595343fbd49ae8 /actionpack | |
parent | 8526e9bed21a119266e886c3316d3fe10c9af5ce (diff) | |
download | rails-3e4a69e52d8c8f0335e0ddbb46fe21009b962334.tar.gz rails-3e4a69e52d8c8f0335e0ddbb46fe21009b962334.tar.bz2 rails-3e4a69e52d8c8f0335e0ddbb46fe21009b962334.zip |
Hand off the interlock to the new thread in AC::Live
Most importantly, the original request thread must yield its share lock
while waiting for the live thread to commit -- otherwise a request's
base and live threads can deadlock against each other.
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/lib/action_controller/metal/live.rb | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index acc4507b2d..fc20e7a421 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -238,34 +238,39 @@ module ActionController # response code and headers back up the rack stack, and still process # the body in parallel with sending data to the client new_controller_thread { - t2 = Thread.current - - # 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) - rescue => e - if @_response.committed? - begin - @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html - @_response.stream.call_on_error - rescue => exception - log_error(exception) - ensure - log_error(e) - @_response.stream.close + ActiveSupport::Dependencies.interlock.running do + t2 = Thread.current + + # 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) + rescue => e + if @_response.committed? + begin + @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html + @_response.stream.call_on_error + rescue => exception + log_error(exception) + ensure + log_error(e) + @_response.stream.close + end + else + error = e end - else - error = e + ensure + @_response.commit! end - ensure - @_response.commit! end } - @_response.await_commit + ActiveSupport::Dependencies.interlock.permit_concurrent_loads do + @_response.await_commit + end + raise error if error end |