mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Puma::ControlCLI - allow refork command to be sent as a request (#2868)
* Puma::ControlCLI - allow refork command to be sent as a request * Puma::ControlCLI - add signal only commands * Puma::ControlCLI - check whether signal is available
This commit is contained in:
parent
2a694a341b
commit
6543f0959b
6 changed files with 107 additions and 14 deletions
|
@ -39,6 +39,9 @@ module Puma
|
|||
when 'phased-restart'
|
||||
@launcher.phased_restart ? 200 : 404
|
||||
|
||||
when 'refork'
|
||||
@launcher.refork ? 200 : 404
|
||||
|
||||
when 'reload-worker-directory'
|
||||
@launcher.send(:reload_worker_directory) ? 200 : 404
|
||||
|
||||
|
|
|
@ -17,26 +17,30 @@ module Puma
|
|||
CMD_PATH_SIG_MAP = {
|
||||
'gc' => nil,
|
||||
'gc-stats' => nil,
|
||||
'halt' => 'SIGQUIT',
|
||||
'phased-restart' => 'SIGUSR1',
|
||||
'refork' => 'SIGURG',
|
||||
'halt' => 'SIGQUIT',
|
||||
'info' => 'SIGINFO',
|
||||
'phased-restart' => 'SIGUSR1',
|
||||
'refork' => 'SIGURG',
|
||||
'reload-worker-directory' => nil,
|
||||
'restart' => 'SIGUSR2',
|
||||
'reopen-log' => 'SIGHUP',
|
||||
'restart' => 'SIGUSR2',
|
||||
'start' => nil,
|
||||
'stats' => nil,
|
||||
'status' => '',
|
||||
'stop' => 'SIGTERM',
|
||||
'thread-backtraces' => nil
|
||||
'stop' => 'SIGTERM',
|
||||
'thread-backtraces' => nil,
|
||||
'worker-count-down' => 'SIGTTOU',
|
||||
'worker-count-up' => 'SIGTTIN'
|
||||
}.freeze
|
||||
|
||||
# @deprecated 6.0.0
|
||||
COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
|
||||
|
||||
# commands that cannot be used in a request
|
||||
NO_REQ_COMMANDS = %w{refork}.freeze
|
||||
NO_REQ_COMMANDS = %w[info reopen-log worker-count-down worker-count-up].freeze
|
||||
|
||||
# @version 5.0.0
|
||||
PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}.freeze
|
||||
PRINTABLE_COMMANDS = %w[gc-stats stats thread-backtraces].freeze
|
||||
|
||||
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
||||
@state = nil
|
||||
|
@ -185,8 +189,6 @@ module Puma
|
|||
|
||||
if @command == 'status'
|
||||
message 'Puma is started'
|
||||
elsif NO_REQ_COMMANDS.include? @command
|
||||
raise "Invalid request command: #{@command}"
|
||||
else
|
||||
url = "/#{@command}"
|
||||
|
||||
|
@ -242,7 +244,11 @@ module Puma
|
|||
@stdout.flush unless @stdout.sync
|
||||
return
|
||||
elsif sig.start_with? 'SIG'
|
||||
Process.kill sig, @pid
|
||||
if Signal.list.key? sig.sub(/\ASIG/, '')
|
||||
Process.kill sig, @pid
|
||||
else
|
||||
raise "Signal '#{sig}' not available'"
|
||||
end
|
||||
elsif @command == 'status'
|
||||
begin
|
||||
Process.kill 0, @pid
|
||||
|
@ -268,7 +274,7 @@ module Puma
|
|||
return start if @command == 'start'
|
||||
prepare_configuration
|
||||
|
||||
if Puma.windows? || @control_url
|
||||
if Puma.windows? || @control_url && !NO_REQ_COMMANDS.include?(@command)
|
||||
send_request
|
||||
else
|
||||
send_signal
|
||||
|
|
|
@ -163,6 +163,17 @@ module Puma
|
|||
true
|
||||
end
|
||||
|
||||
# Begin a refork if supported
|
||||
def refork
|
||||
if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
|
||||
@runner.fork_worker!
|
||||
true
|
||||
else
|
||||
log "* refork called but not available."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Run the server. This blocks until the server is stopped
|
||||
def run
|
||||
previous_env = get_env
|
||||
|
|
|
@ -229,7 +229,7 @@ RUBY
|
|||
end
|
||||
|
||||
# use three workers to keep accepting clients
|
||||
def test_refork
|
||||
def test_fork_worker_on_refork
|
||||
refork = Tempfile.new 'refork'
|
||||
wrkrs = 3
|
||||
cli_server "-w #{wrkrs} test/rackup/hello_with_delay.ru", config: <<RUBY
|
||||
|
|
|
@ -93,6 +93,43 @@ class TestIntegrationPumactl < TestIntegration
|
|||
@server = nil
|
||||
end
|
||||
|
||||
def test_refork_cluster
|
||||
skip_unless :fork
|
||||
wrkrs = 3
|
||||
cli_server "-q -w #{wrkrs} test/rackup/sleep.ru --control-url unix://#{@control_path} --control-token #{TOKEN} -S #{@state_path}",
|
||||
config: 'fork_worker 50',
|
||||
unix: true
|
||||
|
||||
start = Time.now
|
||||
|
||||
s = UNIXSocket.new @bind_path
|
||||
@ios_to_close << s
|
||||
s << "GET /sleep1 HTTP/1.0\r\n\r\n"
|
||||
|
||||
# Get the PIDs of the phase 0 workers.
|
||||
phase0_worker_pids = get_worker_pids 0, wrkrs
|
||||
assert File.exist? @bind_path
|
||||
|
||||
cli_pumactl "refork", unix: true
|
||||
|
||||
# Get the PIDs of the phase 1 workers.
|
||||
phase1_worker_pids = get_worker_pids 1, wrkrs - 1
|
||||
|
||||
msg = "phase 0 pids #{phase0_worker_pids.inspect} phase 1 pids #{phase1_worker_pids.inspect}"
|
||||
|
||||
assert_equal wrkrs , phase0_worker_pids.length, msg
|
||||
assert_equal wrkrs - 1, phase1_worker_pids.length, msg
|
||||
assert_empty phase0_worker_pids & phase1_worker_pids, "#{msg}\nBoth workers should be replaced with new"
|
||||
assert File.exist?(@bind_path), "Bind path must exist after phased refork"
|
||||
|
||||
cli_pumactl "stop", unix: true
|
||||
|
||||
_, status = Process.wait2(@pid)
|
||||
assert_equal 0, status
|
||||
assert_operator Time.now - start, :<, (DARWIN ? 8 : 6)
|
||||
@server = nil
|
||||
end
|
||||
|
||||
def test_prune_bundler_with_multiple_workers
|
||||
skip_unless :fork
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class TestPumaControlCli < TestConfigFileBase
|
|||
|
||||
def teardown
|
||||
@wait.close
|
||||
@ready.close
|
||||
@ready.close unless @ready.closed?
|
||||
end
|
||||
|
||||
def with_config_file(path_to_config, port)
|
||||
|
@ -187,6 +187,42 @@ class TestPumaControlCli < TestConfigFileBase
|
|||
assert_kind_of Thread, t.join, "server didn't stop"
|
||||
end
|
||||
|
||||
# This checks that a 'signal only' command is sent
|
||||
# they are defined by the `Puma::ControlCLI::NO_REQ_COMMANDS` array
|
||||
# test is skipped unless NO_REQ_COMMANDS is defined
|
||||
def test_control_url_with_signal_only_cmd
|
||||
skip_if :windows
|
||||
skip unless defined? Puma::ControlCLI::NO_REQ_COMMANDS
|
||||
host = "127.0.0.1"
|
||||
port = UniquePort.call
|
||||
url = "tcp://#{host}:#{port}/"
|
||||
|
||||
opts = [
|
||||
"--control-url", url,
|
||||
"--control-token", "ctrl",
|
||||
"--config-file", "test/config/app.rb",
|
||||
"--pid", "1234"
|
||||
]
|
||||
cmd = Puma::ControlCLI::NO_REQ_COMMANDS.first
|
||||
log = ''.dup
|
||||
control_cli = Puma::ControlCLI.new (opts + [cmd]), @ready, @ready
|
||||
|
||||
def control_cli.send_signal
|
||||
message "send_signal #{@command}\n"
|
||||
end
|
||||
def control_cli.send_request
|
||||
message "send_request #{@command}\n"
|
||||
end
|
||||
|
||||
control_cli.run
|
||||
@ready.close
|
||||
|
||||
log = @wait.read
|
||||
|
||||
assert_includes log, "send_signal #{cmd}"
|
||||
refute_includes log, 'send_request'
|
||||
end
|
||||
|
||||
def test_control_ssl
|
||||
skip_unless :ssl
|
||||
|
||||
|
|
Loading…
Reference in a new issue