1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Add thread reaping to thread pool

This commit is contained in:
Ole Michaelis 2015-05-19 16:14:30 +02:00
parent 6479e6b26b
commit 5e95791cca
3 changed files with 99 additions and 0 deletions

View file

@ -39,6 +39,7 @@ module Puma
attr_accessor :max_threads
attr_accessor :persistent_timeout
attr_accessor :auto_trim_time
attr_accessor :reaping_time
attr_accessor :first_data_timeout
# Create a server for the rack app +app+.
@ -60,6 +61,7 @@ module Puma
@min_threads = 0
@max_threads = 16
@auto_trim_time = 1
@reaping_time = 1
@thread = nil
@thread_pool = nil
@ -274,6 +276,10 @@ module Puma
@reactor.run_in_thread
end
if @reaping_time
@thread_pool.auto_reap!(@reaping_time)
end
if @auto_trim_time
@thread_pool.auto_trim!(@auto_trim_time)
end

View file

@ -33,6 +33,7 @@ module Puma
@workers = []
@auto_trim = nil
@reaper = nil
@mutex.synchronize do
@min.times { spawn_thread }
@ -155,6 +156,21 @@ module Puma
end
end
# If there are dead threads in the pool make them go away while decreasing
# spwaned counter so that new healty threads could be created again.
def reap
@mutex.synchronize do
dead_workers = @workers.reject(&:alive?)
dead_workers.each do |worker|
worker.kill
@spawned -= 1
end
@workers -= dead_workers
end
end
class AutoTrim
def initialize(pool, timeout)
@pool = pool
@ -184,6 +200,35 @@ module Puma
@auto_trim.start!
end
class Reaper
def initialize(pool, timeout)
@pool = pool
@timeout = timeout
@running = false
end
def start!
@running = true
@thread = Thread.new do
while @running
@pool.reap
sleep @timeout
end
end
end
def stop
@running = false
@thread.wakeup
end
end
def auto_reap!(timeout=5)
@reaper = Reaper.new(self, timeout)
@reaper.start!
end
# Tell all threads in the pool to exit and wait for them to finish.
#
def shutdown
@ -193,6 +238,7 @@ module Puma
@not_full.broadcast
@auto_trim.stop if @auto_trim
@reaper.stop if @reaper
end
# Use this instead of #each so that we don't stop in the middle

View file

@ -179,4 +179,51 @@ class TestThreadPool < Test::Unit::TestCase
assert_equal [], values.compact
end
def test_reap_only_dead_threads
pool = new_pool(2,2) { Thread.current.kill }
assert_equal 2, pool.spawned
pool << 1
pause
assert_equal 2, pool.spawned
pool.reap
assert_equal 1, pool.spawned
pool << 2
pause
assert_equal 1, pool.spawned
pool.reap
assert_equal 0, pool.spawned
end
def test_auto_reap_dead_threads
pool = new_pool(2,2) { Thread.current.kill }
assert_equal 2, pool.spawned
pool << 1
pool << 2
pause
assert_equal 2, pool.spawned
pool.auto_reap! 1
sleep 1
pause
assert_equal 0, pool.spawned
end
end