mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Use IsolatedExecutionState
across Active Support
Ref: https://github.com/rails/rails/pull/43596 This allow users to declare wether their unit of work is isolated by fibers or by threads. `PerThreadRegistry` and `thread_mattr_accessor` were intentionally left out as they require documentation change. I'll submit them in separate pull requests.
This commit is contained in:
parent
3b01e92d52
commit
0ea374c81f
11 changed files with 54 additions and 26 deletions
|
@ -17,7 +17,7 @@ class Date
|
|||
# If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
|
||||
# If no config.beginning_of_week was specified, returns :monday.
|
||||
def beginning_of_week
|
||||
Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
|
||||
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] || beginning_of_week_default || :monday
|
||||
end
|
||||
|
||||
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
|
||||
|
@ -25,7 +25,7 @@ class Date
|
|||
# This method accepts any of the following day symbols:
|
||||
# :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
|
||||
def beginning_of_week=(week_start)
|
||||
Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
|
||||
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] = find_beginning_of_week!(week_start)
|
||||
end
|
||||
|
||||
# Returns week start day symbol (e.g. :monday), or raises an +ArgumentError+ for invalid day symbol.
|
||||
|
|
|
@ -12,7 +12,7 @@ class Time
|
|||
# Returns the TimeZone for the current request, if this has been set (via Time.zone=).
|
||||
# If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
|
||||
def zone
|
||||
Thread.current[:time_zone] || zone_default
|
||||
::ActiveSupport::IsolatedExecutionState[:time_zone] || zone_default
|
||||
end
|
||||
|
||||
# Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
|
||||
|
@ -39,7 +39,7 @@ class Time
|
|||
# end
|
||||
# end
|
||||
def zone=(time_zone)
|
||||
Thread.current[:time_zone] = find_zone!(time_zone)
|
||||
::ActiveSupport::IsolatedExecutionState[:time_zone] = find_zone!(time_zone)
|
||||
end
|
||||
|
||||
# Allows override of <tt>Time.zone</tt> locally inside supplied block;
|
||||
|
|
|
@ -46,7 +46,7 @@ module ActiveSupport
|
|||
|
||||
private
|
||||
def store
|
||||
Thread.current[:active_support_execution_context] ||= {}
|
||||
IsolatedExecutionState[:active_support_execution_context] ||= {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -113,11 +113,11 @@ module ActiveSupport
|
|||
self.active = Concurrent::Hash.new
|
||||
|
||||
def self.active? # :nodoc:
|
||||
@active[Thread.current]
|
||||
@active[IsolatedExecutionState.unique_id]
|
||||
end
|
||||
|
||||
def run! # :nodoc:
|
||||
self.class.active[Thread.current] = true
|
||||
self.class.active[IsolatedExecutionState.unique_id] = true
|
||||
run
|
||||
end
|
||||
|
||||
|
@ -132,7 +132,7 @@ module ActiveSupport
|
|||
def complete!
|
||||
complete
|
||||
ensure
|
||||
self.class.active.delete Thread.current
|
||||
self.class.active.delete(IsolatedExecutionState.unique_id)
|
||||
end
|
||||
|
||||
def complete # :nodoc:
|
||||
|
|
|
@ -25,6 +25,10 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
def unique_id
|
||||
self[:__id__] ||= Object.new
|
||||
end
|
||||
|
||||
def [](key)
|
||||
current[key]
|
||||
end
|
||||
|
|
|
@ -18,8 +18,7 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def local_level
|
||||
# Note: Thread#[] is fiber-local
|
||||
Thread.current[:logger_thread_safe_level]
|
||||
IsolatedExecutionState[:logger_thread_safe_level]
|
||||
end
|
||||
|
||||
def local_level=(level)
|
||||
|
@ -31,7 +30,7 @@ module ActiveSupport
|
|||
else
|
||||
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
||||
end
|
||||
Thread.current[:logger_thread_safe_level] = level
|
||||
IsolatedExecutionState[:logger_thread_safe_level] = level
|
||||
end
|
||||
|
||||
def level
|
||||
|
|
|
@ -226,12 +226,12 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def start(name, id, payload)
|
||||
timestack = Thread.current[:_timestack] ||= []
|
||||
timestack = IsolatedExecutionState[:_timestack] ||= []
|
||||
timestack.push Time.now
|
||||
end
|
||||
|
||||
def finish(name, id, payload)
|
||||
timestack = Thread.current[:_timestack]
|
||||
timestack = IsolatedExecutionState[:_timestack]
|
||||
started = timestack.pop
|
||||
@delegate.call(name, started, Time.now, id, payload)
|
||||
end
|
||||
|
@ -243,12 +243,12 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def start(name, id, payload)
|
||||
timestack = Thread.current[:_timestack_monotonic] ||= []
|
||||
timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
|
||||
timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
|
||||
def finish(name, id, payload)
|
||||
timestack = Thread.current[:_timestack_monotonic]
|
||||
timestack = IsolatedExecutionState[:_timestack_monotonic]
|
||||
started = timestack.pop
|
||||
@delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
|
||||
end
|
||||
|
@ -256,14 +256,14 @@ module ActiveSupport
|
|||
|
||||
class EventObject < Evented
|
||||
def start(name, id, payload)
|
||||
stack = Thread.current[:_event_stack] ||= []
|
||||
stack = IsolatedExecutionState[:_event_stack] ||= []
|
||||
event = build_event name, id, payload
|
||||
event.start!
|
||||
stack.push event
|
||||
end
|
||||
|
||||
def finish(name, id, payload)
|
||||
stack = Thread.current[:_event_stack]
|
||||
stack = IsolatedExecutionState[:_event_stack]
|
||||
event = stack.pop
|
||||
event.payload = payload
|
||||
event.finish!
|
||||
|
|
|
@ -57,7 +57,7 @@ module ActiveSupport
|
|||
def current_tags
|
||||
# We use our object ID here to avoid conflicting with other instances
|
||||
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
|
||||
Thread.current[thread_key] ||= []
|
||||
IsolatedExecutionState[thread_key] ||= []
|
||||
end
|
||||
|
||||
def tags_text
|
||||
|
|
|
@ -181,11 +181,11 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def current_thread_backend
|
||||
Thread.current[:xml_mini_backend]
|
||||
IsolatedExecutionState[:xml_mini_backend]
|
||||
end
|
||||
|
||||
def current_thread_backend=(name)
|
||||
Thread.current[:xml_mini_backend] = name && cast_backend_name_to_module(name)
|
||||
IsolatedExecutionState[:xml_mini_backend] = name && cast_backend_name_to_module(name)
|
||||
end
|
||||
|
||||
def cast_backend_name_to_module(name)
|
||||
|
|
|
@ -1205,13 +1205,11 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase
|
|||
|
||||
def test_time_zone_setter_is_thread_safe
|
||||
Time.use_zone "Paris" do
|
||||
t1 = Thread.new { Time.zone = "Alaska" }.join
|
||||
t2 = Thread.new { Time.zone = "Hawaii" }.join
|
||||
assert t1.stop?, "Thread 1 did not finish running"
|
||||
assert t2.stop?, "Thread 2 did not finish running"
|
||||
t1 = Thread.new { Time.zone = "Alaska"; Time.zone }
|
||||
t2 = Thread.new { Time.zone = "Hawaii"; Time.zone }
|
||||
assert_equal ActiveSupport::TimeZone["Paris"], Time.zone
|
||||
assert_equal ActiveSupport::TimeZone["Alaska"], t1[:time_zone]
|
||||
assert_equal ActiveSupport::TimeZone["Hawaii"], t2[:time_zone]
|
||||
assert_equal ActiveSupport::TimeZone["Alaska"], t1.value
|
||||
assert_equal ActiveSupport::TimeZone["Hawaii"], t2.value
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -272,6 +272,9 @@ class LoggerTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_logger_level_main_fiber_safety
|
||||
previous_isolation_level = ActiveSupport::IsolatedExecutionState.isolation_level
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
|
||||
|
||||
@logger.level = Logger::INFO
|
||||
assert_level(Logger::INFO)
|
||||
|
||||
|
@ -283,9 +286,14 @@ class LoggerTest < ActiveSupport::TestCase
|
|||
assert_level(Logger::ERROR)
|
||||
fiber.resume
|
||||
end
|
||||
ensure
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = previous_isolation_level
|
||||
end
|
||||
|
||||
def test_logger_level_local_fiber_safety
|
||||
previous_isolation_level = ActiveSupport::IsolatedExecutionState.isolation_level
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
|
||||
|
||||
@logger.level = Logger::INFO
|
||||
assert_level(Logger::INFO)
|
||||
|
||||
|
@ -313,6 +321,25 @@ class LoggerTest < ActiveSupport::TestCase
|
|||
end.resume
|
||||
|
||||
assert_level(Logger::INFO)
|
||||
ensure
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = previous_isolation_level
|
||||
end
|
||||
|
||||
def test_logger_level_thread_safety
|
||||
previous_isolation_level = ActiveSupport::IsolatedExecutionState.isolation_level
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = :thread
|
||||
|
||||
@logger.level = Logger::INFO
|
||||
assert_level(Logger::INFO)
|
||||
|
||||
enumerator = Enumerator.new do |yielder|
|
||||
@logger.level = Logger::DEBUG
|
||||
yielder.yield @logger.level
|
||||
end
|
||||
assert_equal Logger::DEBUG, enumerator.next
|
||||
assert_level(Logger::DEBUG)
|
||||
ensure
|
||||
ActiveSupport::IsolatedExecutionState.isolation_level = previous_isolation_level
|
||||
end
|
||||
|
||||
def test_temporarily_logging_at_a_noisier_level
|
||||
|
|
Loading…
Reference in a new issue