diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 2d6ad8f6d9..0658d8601d 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -6,6 +6,12 @@ module ActionView class Digestor @@digest_mutex = Mutex.new + module PerExecutionDigestCacheExpiry + def self.before(target) + ActionView::LookupContext::DetailsKey.clear + end + end + class << self # Supported options: # diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index dfb99f4ea9..42795ca2c7 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -40,7 +40,7 @@ module ActionView initializer "action_view.per_request_digest_cache" do |app| ActiveSupport.on_load(:action_view) do if app.config.consider_all_requests_local - app.executor.to_run { ActionView::LookupContext::DetailsKey.clear } + app.executor.to_run ActionView::Digestor::PerExecutionDigestCacheExpiry end end end diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index 387dd8e9bd..c45c8c1697 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -34,16 +34,14 @@ module ActiveRecord def self.complete(enabled) ActiveRecord::Base.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! unless enabled + + unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? + ActiveRecord::Base.clear_active_connections! + end end def self.install_executor_hooks(executor = ActiveSupport::Executor) executor.register_hook(self) - - executor.to_complete do - unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? - ActiveRecord::Base.clear_active_connections! - end - end end end end diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 4c8b03c9df..3384d12d5b 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -19,6 +19,23 @@ module ActiveSupport set_callback(:complete, *args, &block) end + class RunHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + hook_state[hook] = hook.run + end + end + + class CompleteHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + if hook_state.key?(hook) + hook.complete hook_state[hook] + end + end + alias after before + end + # Register an object to be invoked during both the +run+ and # +complete+ steps. # @@ -29,19 +46,11 @@ module ActiveSupport # invoked in that situation.) def self.register_hook(hook, outer: false) if outer - run_args = [prepend: true] - complete_args = [:after] + to_run RunHook.new(hook), prepend: true + to_complete :after, CompleteHook.new(hook) else - run_args = complete_args = [] - end - - to_run(*run_args) do - hook_state[hook] = hook.run - end - to_complete(*complete_args) do - if hook_state.key?(hook) - hook.complete hook_state[hook] - end + to_run RunHook.new(hook) + to_complete CompleteHook.new(hook) end end diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index 0b56ea008f..d409216206 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -158,6 +158,61 @@ class ExecutorTest < ActiveSupport::TestCase assert_equal :some_state, supplied_state end + def test_hook_insertion_order + invoked = [] + supplied_state = [] + + hook_class = Class.new do + attr_accessor :letter + + define_method(:initialize) do |letter| + self.letter = letter + end + + define_method(:run) do + invoked << :"run_#{letter}" + :"state_#{letter}" + end + + define_method(:complete) do |state| + invoked << :"complete_#{letter}" + supplied_state << state + end + end + + executor.register_hook(hook_class.new(:a)) + executor.register_hook(hook_class.new(:b)) + executor.register_hook(hook_class.new(:c), outer: true) + executor.register_hook(hook_class.new(:d)) + + executor.wrap {} + + assert_equal [:run_c, :run_a, :run_b, :run_d, :complete_a, :complete_b, :complete_d, :complete_c], invoked + assert_equal [:state_a, :state_b, :state_d, :state_c], supplied_state + end + + def test_class_serial_is_unaffected + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + nil + end + end.new + + executor.register_hook(hook) + + before = RubyVM.stat(:class_serial) + executor.wrap {} + executor.wrap {} + executor.wrap {} + after = RubyVM.stat(:class_serial) + + assert_equal before, after + end + def test_separate_classes_can_wrap other_executor = Class.new(ActiveSupport::Executor)