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

Catch exceptions in hooks defined by users (#2155)

* Catch exceptions in run_hooks mehtod

* Add missing unit tests on Configuration#run_hooks method

* History.md: Add note about the bugfix

* Code review: fix wording and introduce a test helper assert_run_hooks
This commit is contained in:
Andrew Konchin 2020-03-10 19:41:17 +02:00 committed by GitHub
parent a04fc21a56
commit 7827a6c741
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 8 deletions

View file

@ -21,6 +21,7 @@
* Preserve `BUNDLE_GEMFILE` env var when using `prune_bundler` (#1893)
* Send 408 request timeout even when queue requests is disabled (#2119)
* Rescue IO::WaitReadable instead of EAGAIN for blocking read (#2121)
* Rescue and log exceptions in hooks defined by users (on_worker_boot, after_worker_fork etc) (#1551)
* Refactor
* Remove unused loader argument from Plugin initializer (#2095)

View file

@ -137,7 +137,7 @@ module Puma
diff.times do
idx = next_worker_index
@launcher.config.run_hooks :before_worker_fork, idx
@launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
pid = fork { worker(idx, master) }
if !pid
@ -149,7 +149,7 @@ module Puma
debug "Spawned worker: #{pid}"
@workers << Worker.new(idx, pid, @phase, @options)
@launcher.config.run_hooks :after_worker_fork, idx
@launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
end
if diff > 0
@ -268,7 +268,7 @@ module Puma
# Invoke any worker boot hooks so they can get
# things in shape before booting the app.
@launcher.config.run_hooks :before_worker_boot, index
@launcher.config.run_hooks :before_worker_boot, index, @launcher.events
server = start_server
@ -310,7 +310,7 @@ module Puma
# Invoke any worker shutdown hooks so they can prevent the worker
# exiting until any background operations are completed
@launcher.config.run_hooks :before_worker_shutdown, index
@launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
ensure
@worker_write << "t#{Process.pid}\n" rescue nil
@worker_write.close
@ -486,7 +486,7 @@ module Puma
@master_read, @worker_write = read, @wakeup
@launcher.config.run_hooks :before_fork, nil
@launcher.config.run_hooks :before_fork, nil, @launcher.events
GC.compact if GC.respond_to?(:compact)
spawn_workers

View file

@ -267,8 +267,15 @@ module Puma
@plugins.create name
end
def run_hooks(key, arg)
@options.all_of(key).each { |b| b.call arg }
def run_hooks(key, arg, events)
@options.all_of(key).each do |b|
begin
b.call arg
rescue => e
events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
events.debug e.backtrace.join("\n")
end
end
end
def self.temp_path

View file

@ -238,7 +238,7 @@ module Puma
end
def restart!
@config.run_hooks :on_restart, self
@config.run_hooks :on_restart, self, @events
if Puma.jruby?
close_binder_listeners

View file

@ -4,6 +4,7 @@ require_relative "helper"
require_relative "helpers/config_file"
require "puma/configuration"
require 'puma/events'
class TestConfigFile < TestConfigFileBase
parallelize_me!
@ -201,6 +202,61 @@ class TestConfigFile < TestConfigFileBase
conf.options[:raise_exception_on_sigterm] = true
assert_equal conf.options[:raise_exception_on_sigterm], true
end
def test_run_hooks_on_restart_hook
assert_run_hooks :on_restart
end
def test_run_hooks_before_worker_fork
assert_run_hooks :before_worker_fork, configured_with: :on_worker_fork
end
def test_run_hooks_after_worker_fork
assert_run_hooks :after_worker_fork
end
def test_run_hooks_before_worker_boot
assert_run_hooks :before_worker_boot, configured_with: :on_worker_boot
end
def test_run_hooks_before_worker_shutdown
assert_run_hooks :before_worker_shutdown, configured_with: :on_worker_shutdown
end
def test_run_hooks_before_fork
assert_run_hooks :before_fork
end
def test_run_hooks_and_exception
conf = Puma::Configuration.new do |c|
c.on_restart do |a|
raise RuntimeError, 'Error from hook'
end
end
conf.load
events = Puma::Events.strings
conf.run_hooks :on_restart, 'ARG', events
expected = /WARNING hook on_restart failed with exception \(RuntimeError\) Error from hook/
assert_match expected, events.stdout.string
end
private
def assert_run_hooks(hook_name, options = {})
configured_with = options[:configured_with] || hook_name
messages = []
conf = Puma::Configuration.new do |c|
c.send(configured_with) do |a|
messages << "#{hook_name} is called with #{a}"
end
end
conf.load
conf.run_hooks hook_name, 'ARG', Puma::Events.strings
assert_equal messages, ["#{hook_name} is called with ARG"]
end
end
# Thread unsafe modification of ENV