From 4e79deeccefa761934067a72aba4cde280316acf Mon Sep 17 00:00:00 2001 From: Katsuya HIDAKA Date: Sat, 23 May 2026 02:56:17 +0900 Subject: Fix flaky IssueNestedSetConcurrencyTest --- .../unit/issue_nested_set_concurrency_test.rb | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/test/unit/issue_nested_set_concurrency_test.rb b/test/unit/issue_nested_set_concurrency_test.rb index 2692ce99f..54459ebf3 100644 --- a/test/unit/issue_nested_set_concurrency_test.rb +++ b/test/unit/issue_nested_set_concurrency_test.rb @@ -23,6 +23,7 @@ class IssueNestedSetConcurrencyTest < ActiveSupport::TestCase self.use_transactional_tests = false def setup + @connection_pool_mutex = Mutex.new skip if sqlite? if mysql? connection = ActiveRecord::Base.connection_db_config.configuration_hash.deep_dup @@ -87,14 +88,14 @@ class IssueNestedSetConcurrencyTest < ActiveSupport::TestCase threads = [] ids_to_remove.each_slice(10) do |ids| threads << Thread.new do - ActiveRecord::Base.connection_pool.with_connection do - begin + begin + with_thread_connection do ids.each do |id| Issue.find(id).update(parent_id: nil) end - rescue => e - Thread.current[:exception] = e.message end + rescue => e + Thread.current[:exception] = e.message end end end @@ -118,17 +119,15 @@ class IssueNestedSetConcurrencyTest < ActiveSupport::TestCase private - def threaded(count, &) + def threaded(count, &block) with_settings :notified_events => [] do threads = [] count.times do |i| threads << Thread.new(i) do - ActiveRecord::Base.connection_pool.with_connection do - begin - yield - rescue => e - Thread.current[:exception] = e.message - end + begin + with_thread_connection(&block) + rescue => e + Thread.current[:exception] = e.message end end end @@ -138,4 +137,15 @@ class IssueNestedSetConcurrencyTest < ActiveSupport::TestCase end end end + + def with_thread_connection(&) + # Active Record updates its connection lease registry when a thread obtains a + # connection for the first time, which can race when test threads start + # together. + @connection_pool_mutex.synchronize do + # Initialize this thread's connection lease before concurrent updates. + ActiveRecord::Base.connection_pool.with_connection { nil } + end + ActiveRecord::Base.connection_pool.with_connection(&) + end end -- 2.52.0