Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add on_thread_exit hook #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/puma/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,23 @@ def on_refork(&block)
@options[:before_refork] << block
end

# Code to run immediately before a thread exits. The worker does not
# accept new requests until this code finishes.
#
# This hook is useful for cleaning up thread local resources when a thread
# is trimmed.
#
# This can be called multiple times to add several hooks.
#
# @example
# on_thread_exit do
# puts 'On thread exit...'
# end
def on_thread_exit(&block)
@options[:before_thread_exit] ||= []
@options[:before_thread_exit] << block
end

# Code to run out-of-band when the worker is idle.
# These hooks run immediately after a request has finished
# processing and there are no busy threads on the worker.
Expand Down
1 change: 1 addition & 0 deletions lib/puma/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def run(background=true, thread_name: 'srv')

@thread_pool.out_of_band_hook = @options[:out_of_band]
@thread_pool.clean_thread_locals = @options[:clean_thread_locals]
@thread_pool.before_thread_exit_hook = @options[:before_thread_exit]

if @queue_requests
@reactor = Reactor.new(@io_selector_backend, &method(:reactor_wakeup))
Expand Down
13 changes: 13 additions & 0 deletions lib/puma/thread_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def initialize(name, min, max, *extra, &block)
attr_reader :spawned, :trim_requested, :waiting
attr_accessor :clean_thread_locals
attr_accessor :out_of_band_hook # @version 5.0.0
attr_accessor :before_thread_exit_hook

def self.clean_thread_locals
Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
Expand Down Expand Up @@ -121,6 +122,7 @@ def spawn_thread
@spawned -= 1
@workers.delete th
not_full.signal
trigger_before_thread_exit_hook
Thread.exit
end

Expand Down Expand Up @@ -158,6 +160,17 @@ def spawn_thread

private :spawn_thread

def trigger_before_thread_exit_hook
return unless before_thread_exit_hook && before_thread_exit_hook.any?

before_thread_exit_hook.each(&:call)
nil
rescue Exception => e
STDERR.puts "Exception calling before_thread_exit_hook: #{e.message} (#{e.class})"
end

private :trigger_before_thread_exit_hook

# @version 5.0.0
def trigger_out_of_band_hook
return false unless out_of_band_hook && out_of_band_hook.any?
Expand Down
4 changes: 4 additions & 0 deletions test/test_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ def test_run_hooks_before_fork
assert_run_hooks :before_fork
end

def test_run_hooks_before_thread_exit
assert_run_hooks :before_thread_exit, configured_with: :on_thread_exit
end

def test_run_hooks_and_exception
conf = Puma::Configuration.new do |c|
c.on_restart do |a|
Expand Down
18 changes: 18 additions & 0 deletions test/test_thread_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@ def test_trim_is_ignored_if_no_waiting_threads
assert_equal 0, pool.trim_requested
end

def test_trim_thread_exit_hook
pool = mutex_pool(0, 1)
exited = Queue.new
pool.before_thread_exit_hook = [
proc do
exited << 1
end
]

pool << 1

assert_equal 1, pool.spawned

pool.trim
assert_equal 0, pool.spawned
assert_equal 1, exited.length
end

def test_autotrim
pool = mutex_pool(1, 2)

Expand Down