diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index 08db278880fe1..3765986567fef 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -30,7 +30,7 @@ def self.run end def self.complete(pools) - pools.each { |pool| pool.disable_query_cache! } + pools.each { |pool| pool.disable_query_cache! unless pool.discarded? } ActiveRecord::Base.connection_handler.each_connection_pool do |pool| pool.release_connection if pool.active_connection? && !pool.connection.transaction_open? diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 43a4031405888..f5c4e8e01962c 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -650,6 +650,37 @@ def test_clear_query_cache_is_called_on_all_connections ActiveRecord::Base.connection_pool.lock_thread = false end + test "query cache callbacks exit gracefully from a fork" do + # Regression test for #51298 + pid = nil + status = nil + + # Run forking Rack app + middleware { |env| + pid = fork + _, status = Process.wait2(pid) if pid.present? + [200, {}, nil] + }.call({}) + + + # Happy path, the fork exit 0 and the main process + # asserts on the exit status of the fork + if pid.nil? + exit 0 + else + assert_equal 0, status.exitstatus + end + rescue + # Unhappy path, the fork exit 1. + # The main process should not reach here, but in case + # something's wrong we need to re-raise the error. + if pid.nil? + exit 1 + else + raise + end + end + private def with_temporary_connection_pool(&block) pool_config = ActiveRecord::Base.connection.pool.pool_config