diff --git a/lib/discourse.rb b/lib/discourse.rb index 4f8ae8e7246..f275f93c322 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -500,6 +500,9 @@ module Discourse ObjectSpace.each_object(ActiveRecord::ConnectionAdapters::ConnectionPool) { |pool| pools << pool } pools.each do |pool| + # reap recovers connections that were aborted + # eg a thread died or a dev forgot to check it in + pool.reap pool.drain(idle.seconds, max_age.seconds) end end diff --git a/lib/freedom_patches/pool_drainer.rb b/lib/freedom_patches/pool_drainer.rb index 583358cc4b8..3f99a1c61df 100644 --- a/lib/freedom_patches/pool_drainer.rb +++ b/lib/freedom_patches/pool_drainer.rb @@ -25,31 +25,23 @@ class ActiveRecord::ConnectionAdapters::ConnectionPool # drain all idle connections # if idle_time is specified only connections idle for N seconds will be drained def drain(idle_time = nil, max_age = nil) - synchronize do - if @available && @connections - @available.clear - @connections.delete_if do |conn| - try_drain?(conn, idle_time, max_age) - end + return if !(@connections && @available) - @connections.each do |conn| - @available.add conn if !conn.in_use? - end + idle_connections = synchronize do + @connections.select do |conn| + !conn.in_use? && ((idle_time && conn.last_use <= idle_time.seconds.ago) || (max_age && conn.first_use < max_age.seconds.ago)) + end.each do |conn| + conn.lease + + @available.delete conn + @connections.delete conn end end + idle_connections.each do |conn| + conn.disconnect! + end + end - private - - def try_drain?(conn, idle_time, max_age) - if !conn.in_use? - if !idle_time || conn.last_use < idle_time.seconds.ago || (max_age && conn.first_use < max_age.seconds.ago) - conn.disconnect! - return true - end - end - - false - end end diff --git a/spec/components/freedom_patches/pool_drainer_spec.rb b/spec/components/freedom_patches/pool_drainer_spec.rb index 32fc98dc85a..f538eeed4c6 100644 --- a/spec/components/freedom_patches/pool_drainer_spec.rb +++ b/spec/components/freedom_patches/pool_drainer_spec.rb @@ -6,7 +6,10 @@ describe 'pool drainer' do end it 'can correctly drain the connection pool' do - pool.drain + + pool.reap + pool.drain(0) + old = pool.connections.length expect(old).to eq(1) @@ -16,7 +19,9 @@ describe 'pool drainer' do end.join expect(pool.connections.length).to eq(old + 1) - pool.drain + + freeze_time 1.second.from_now + pool.drain(0) expect(pool.connections.length).to eq(old) end