rails/activesupport/test/isolated_execution_state_test.rb
Jean Boussier 540d2f41f6 Introduce ActiveSupport::IsolatedExecutionState for internal use
Many places in Active Support and Rails in general use `Thread.current#[]`
to store "request (or job) local data". This often cause problems with
`Enumerator` because it runs in a different fiber.

On the other hand, some places migrated to `Thread#thread_variable_get`
which cause issues with fiber based servers (`falcon`).

Based on this, I believe the isolation level should be an application
configuration.

For backward compatibility it could ship with `:fiber` isolation as a default
but longer term :thread would make more sense as it would work fine for
all deployment targets except falcon.

Ref: https://github.com/rails/rails/pull/38905
Ref: https://github.com/rails/rails/pull/39428
Ref: https://github.com/rails/rails/pull/34495
(and possibly many others)
2021-11-18 15:55:15 +01:00

57 lines
2.0 KiB
Ruby

# frozen_string_literal: true
require_relative "abstract_unit"
class IsolatedExecutionStateTest < ActiveSupport::TestCase
setup do
ActiveSupport::IsolatedExecutionState.clear
@original_isolation_level = ActiveSupport::IsolatedExecutionState.isolation_level
end
teardown do
ActiveSupport::IsolatedExecutionState.clear
ActiveSupport::IsolatedExecutionState.isolation_level = @original_isolation_level
end
test "#[] when isolation level is :fiber" do
ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
ActiveSupport::IsolatedExecutionState[:test] = 42
assert_equal 42, ActiveSupport::IsolatedExecutionState[:test]
enumerator = Enumerator.new do |yielder|
yielder.yield ActiveSupport::IsolatedExecutionState[:test]
end
assert_nil enumerator.next
assert_nil Thread.new { ActiveSupport::IsolatedExecutionState[:test] }.value
end
test "#[] when isolation level is :thread" do
ActiveSupport::IsolatedExecutionState.isolation_level = :thread
ActiveSupport::IsolatedExecutionState[:test] = 42
assert_equal 42, ActiveSupport::IsolatedExecutionState[:test]
enumerator = Enumerator.new do |yielder|
yielder.yield ActiveSupport::IsolatedExecutionState[:test]
end
assert_equal 42, enumerator.next
assert_nil Thread.new { ActiveSupport::IsolatedExecutionState[:test] }.value
end
test "changing the isolation level clear the old store" do
original = ActiveSupport::IsolatedExecutionState.isolation_level
other = ActiveSupport::IsolatedExecutionState.isolation_level == :fiber ? :thread : :fiber
ActiveSupport::IsolatedExecutionState[:test] = 42
ActiveSupport::IsolatedExecutionState.isolation_level = original
assert_equal 42, ActiveSupport::IsolatedExecutionState[:test]
ActiveSupport::IsolatedExecutionState.isolation_level = other
assert_nil ActiveSupport::IsolatedExecutionState[:test]
ActiveSupport::IsolatedExecutionState.isolation_level = original
assert_nil ActiveSupport::IsolatedExecutionState[:test]
end
end