mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Add worker_check_interval configuration option (#2759)
Co-authored-by: Olivier Bellone <olivier@bellone.fr>
This commit is contained in:
parent
909f51e711
commit
1008c36a4a
8 changed files with 43 additions and 8 deletions
|
@ -135,7 +135,7 @@ module Puma
|
||||||
def check_workers
|
def check_workers
|
||||||
return if @next_check >= Time.now
|
return if @next_check >= Time.now
|
||||||
|
|
||||||
@next_check = Time.now + Const::WORKER_CHECK_INTERVAL
|
@next_check = Time.now + @options[:worker_check_interval]
|
||||||
|
|
||||||
timeout_workers
|
timeout_workers
|
||||||
wait_workers
|
wait_workers
|
||||||
|
|
|
@ -130,7 +130,7 @@ module Puma
|
||||||
Puma::Util.purge_interrupt_queue
|
Puma::Util.purge_interrupt_queue
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
sleep Const::WORKER_CHECK_INTERVAL
|
sleep @options[:worker_check_interval]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
server_thread.join
|
server_thread.join
|
||||||
|
|
|
@ -11,6 +11,7 @@ module Puma
|
||||||
|
|
||||||
DefaultTCPHost = "0.0.0.0"
|
DefaultTCPHost = "0.0.0.0"
|
||||||
DefaultTCPPort = 9292
|
DefaultTCPPort = 9292
|
||||||
|
DefaultWorkerCheckInterval = 5
|
||||||
DefaultWorkerTimeout = 60
|
DefaultWorkerTimeout = 60
|
||||||
DefaultWorkerShutdownTimeout = 30
|
DefaultWorkerShutdownTimeout = 30
|
||||||
end
|
end
|
||||||
|
@ -195,6 +196,7 @@ module Puma
|
||||||
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
||||||
:silence_single_worker_warning => false,
|
:silence_single_worker_warning => false,
|
||||||
:mode => :http,
|
:mode => :http,
|
||||||
|
:worker_check_interval => DefaultWorkerCheckInterval,
|
||||||
:worker_timeout => DefaultWorkerTimeout,
|
:worker_timeout => DefaultWorkerTimeout,
|
||||||
:worker_boot_timeout => DefaultWorkerTimeout,
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
||||||
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
||||||
|
|
|
@ -235,9 +235,6 @@ module Puma
|
||||||
|
|
||||||
EARLY_HINTS = "rack.early_hints".freeze
|
EARLY_HINTS = "rack.early_hints".freeze
|
||||||
|
|
||||||
# Minimum interval to checks worker health
|
|
||||||
WORKER_CHECK_INTERVAL = 5
|
|
||||||
|
|
||||||
# Illegal character in the key or value of response header
|
# Illegal character in the key or value of response header
|
||||||
DQUOTE = "\"".freeze
|
DQUOTE = "\"".freeze
|
||||||
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
||||||
|
|
|
@ -736,6 +736,19 @@ module Puma
|
||||||
@options[:tag] = string.to_s
|
@options[:tag] = string.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Change the default interval for checking workers.
|
||||||
|
#
|
||||||
|
# The default value is 5 seconds.
|
||||||
|
#
|
||||||
|
# @note Cluster mode only.
|
||||||
|
# @example
|
||||||
|
# worker_check_interval 5
|
||||||
|
# @see Puma::Cluster#check_workers
|
||||||
|
#
|
||||||
|
def worker_check_interval(interval)
|
||||||
|
@options[:worker_check_interval] = Integer(interval)
|
||||||
|
end
|
||||||
|
|
||||||
# Verifies that all workers have checked in to the master process within
|
# Verifies that all workers have checked in to the master process within
|
||||||
# the given timeout. If not the worker process will be restarted. This is
|
# the given timeout. If not the worker process will be restarted. This is
|
||||||
# not a request timeout, it is to protect against a hung or dead process.
|
# not a request timeout, it is to protect against a hung or dead process.
|
||||||
|
@ -750,7 +763,7 @@ module Puma
|
||||||
#
|
#
|
||||||
def worker_timeout(timeout)
|
def worker_timeout(timeout)
|
||||||
timeout = Integer(timeout)
|
timeout = Integer(timeout)
|
||||||
min = Const::WORKER_CHECK_INTERVAL
|
min = @options.fetch(:worker_check_interval, Puma::ConfigDefault::DefaultWorkerCheckInterval)
|
||||||
|
|
||||||
if timeout <= min
|
if timeout <= min
|
||||||
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "puma/control_cli"
|
require "puma/control_cli"
|
||||||
|
require "json"
|
||||||
require "open3"
|
require "open3"
|
||||||
require "io/wait"
|
require "io/wait"
|
||||||
require_relative 'tmp_path'
|
require_relative 'tmp_path'
|
||||||
|
@ -255,6 +256,11 @@ class TestIntegration < Minitest::Test
|
||||||
r
|
r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_stats
|
||||||
|
read_pipe = cli_pumactl "stats"
|
||||||
|
JSON.parse(read_pipe.readlines.last)
|
||||||
|
end
|
||||||
|
|
||||||
def hot_restart_does_not_drop_connections(num_threads: 1, total_requests: 500)
|
def hot_restart_does_not_drop_connections(num_threads: 1, total_requests: 500)
|
||||||
skipped = true
|
skipped = true
|
||||||
skip_if :jruby, suffix: <<-MSG
|
skip_if :jruby, suffix: <<-MSG
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
require_relative "helper"
|
require_relative "helper"
|
||||||
require_relative "helpers/integration"
|
require_relative "helpers/integration"
|
||||||
|
|
||||||
|
require "time"
|
||||||
|
|
||||||
class TestIntegrationCluster < TestIntegration
|
class TestIntegrationCluster < TestIntegration
|
||||||
parallelize_me! if ::Puma.mri?
|
parallelize_me! if ::Puma.mri?
|
||||||
|
|
||||||
|
@ -147,6 +149,21 @@ class TestIntegrationCluster < TestIntegration
|
||||||
worker_respawn { |phase0_worker_pids| Process.kill :USR1, @pid }
|
worker_respawn { |phase0_worker_pids| Process.kill :USR1, @pid }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_worker_check_interval
|
||||||
|
@control_tcp_port = UniquePort.call
|
||||||
|
worker_check_interval = 1
|
||||||
|
|
||||||
|
cli_server "-w 1 -t 1:1 --control-url tcp://#{HOST}:#{@control_tcp_port} --control-token #{TOKEN} test/rackup/hello.ru", config: "worker_check_interval #{worker_check_interval}"
|
||||||
|
|
||||||
|
sleep worker_check_interval + 1
|
||||||
|
last_checkin_1 = Time.parse(get_stats["worker_status"].first["last_checkin"])
|
||||||
|
|
||||||
|
sleep worker_check_interval + 1
|
||||||
|
last_checkin_2 = Time.parse(get_stats["worker_status"].first["last_checkin"])
|
||||||
|
|
||||||
|
assert(last_checkin_2 > last_checkin_1)
|
||||||
|
end
|
||||||
|
|
||||||
def test_worker_boot_timeout
|
def test_worker_boot_timeout
|
||||||
timeout = 1
|
timeout = 1
|
||||||
worker_timeout(timeout, 2, "worker failed to boot within \\\d+ seconds", "worker_boot_timeout #{timeout}; on_worker_boot { sleep #{timeout + 1} }")
|
worker_timeout(timeout, 2, "worker failed to boot within \\\d+ seconds", "worker_boot_timeout #{timeout}; on_worker_boot { sleep #{timeout + 1} }")
|
||||||
|
@ -154,7 +171,7 @@ class TestIntegrationCluster < TestIntegration
|
||||||
|
|
||||||
def test_worker_timeout
|
def test_worker_timeout
|
||||||
skip 'Thread#name not available' unless Thread.current.respond_to?(:name)
|
skip 'Thread#name not available' unless Thread.current.respond_to?(:name)
|
||||||
timeout = Puma::Const::WORKER_CHECK_INTERVAL + 1
|
timeout = Puma::ConfigDefault::DefaultWorkerCheckInterval + 1
|
||||||
worker_timeout(timeout, 1, "worker failed to check in within \\\d+ seconds", <<RUBY)
|
worker_timeout(timeout, 1, "worker failed to check in within \\\d+ seconds", <<RUBY)
|
||||||
worker_timeout #{timeout}
|
worker_timeout #{timeout}
|
||||||
on_worker_boot do
|
on_worker_boot do
|
||||||
|
|
|
@ -148,7 +148,7 @@ class TestLauncher < Minitest::Test
|
||||||
end
|
end
|
||||||
launcher = launcher(conf)
|
launcher = launcher(conf)
|
||||||
Thread.new do
|
Thread.new do
|
||||||
sleep Puma::Const::WORKER_CHECK_INTERVAL + 1
|
sleep Puma::ConfigDefault::DefaultWorkerCheckInterval + 1
|
||||||
status = Puma.stats_hash[:worker_status].first[:last_status]
|
status = Puma.stats_hash[:worker_status].first[:last_status]
|
||||||
Puma::Server::STAT_METHODS.each do |stat|
|
Puma::Server::STAT_METHODS.each do |stat|
|
||||||
assert_includes status, stat
|
assert_includes status, stat
|
||||||
|
|
Loading…
Reference in a new issue