1
0
Fork 0
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:
Olivier Bellone 2021-12-11 13:58:05 -08:00 committed by GitHub
parent 909f51e711
commit 1008c36a4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 8 deletions

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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})"

View file

@ -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

View file

@ -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

View file

@ -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