Skip to content

Commit

Permalink
Merge pull request #44499 from Shopify/ac-live-thread-copy
Browse files Browse the repository at this point in the history
Copy over the IsolatedExecutionState in AC::Live
  • Loading branch information
byroot committed Feb 21, 2022
2 parents c21c413 + d327678 commit 7b1f65e
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 0 deletions.
10 changes: 10 additions & 0 deletions actionpack/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
* Fix `ActionContoller::Live` to copy the IsolatedExecutionState in the ephemeral thread.

Since it's inception `ActionContoller::Live` has been copying thread local variables
to keep things such as `CurrentAttributes` set from middlewares working in the controller action.

With the introduction of `IsolatedExecutionState` in 7.0, some of that global state was lost in
`ActionContoller::Live` controllers.

*Jean Boussier*

* Fix setting `trailing_slash: true` in route definition.

```ruby
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_controller/metal/live.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ def process(name)
# 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 }
ActiveSupport::IsolatedExecutionState.share_with(t1)

begin
super(name)
Expand Down
17 changes: 17 additions & 0 deletions actionpack/test/controller/live_stream_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ class LiveStreamTest < ActionController::TestCase
class Exception < StandardError
end

class CurrentState < ActiveSupport::CurrentAttributes
attribute :id
end

class TestController < ActionController::Base
include ActionController::Live

Expand Down Expand Up @@ -203,6 +207,10 @@ def thread_locals
response.stream.close
end

def isolated_state
render plain: CurrentState.id.inspect
end

def with_stale
render plain: "stale" if stale?(etag: "123", template: false)
end
Expand Down Expand Up @@ -445,6 +453,15 @@ def test_thread_locals_get_copied
get :thread_locals
end

def test_isolated_state_get_copied
@controller.tc = self
CurrentState.id = "isolated_state"

get :isolated_state
assert_equal "isolated_state".inspect, response.body
assert_stream_closed
end

def test_live_stream_default_header
get :default_header
assert response.headers["Content-Type"]
Expand Down
7 changes: 7 additions & 0 deletions activesupport/lib/active_support/isolated_execution_state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ def context
scope.current
end

def share_with(other)
# Action Controller streaming spawns a new thread and copy thread locals.
# We do the same here for backward compatibility, but this is very much a hack
# and streaming should be rethought.
context.active_support_execution_state = other.active_support_execution_state.dup
end

private
def state
context.active_support_execution_state ||= {}
Expand Down

0 comments on commit 7b1f65e

Please sign in to comment.