Skip to content

Commit

Permalink
SIGINFO prints thread backtraces
Browse files Browse the repository at this point in the history
Super basic server test

Add tests for single/cluster

Cleanup
  • Loading branch information
nateberkopec committed Sep 12, 2019
1 parent 3ce98b7 commit 124c76c
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 10 deletions.
8 changes: 6 additions & 2 deletions lib/puma/cluster.rb
Expand Up @@ -273,6 +273,10 @@ def worker(index, master)
server.stop
end

Signal.trap "SIGINFO" do
server.log_thread_status
end

begin
@worker_write << "b#{Process.pid}\n"
rescue SystemCallError, IOError
Expand Down Expand Up @@ -346,8 +350,8 @@ def reload_worker_directory
log "+ Changing to #{dir}"
Dir.chdir dir
end
# Inside of a child process, this will return all zeroes, as @workers is only populated in

# Inside of a child process, this will return all zeroes, as @workers is only populated in
# the master process.
def stats
old_worker_count = @workers.count { |w| w.phase != @phase }
Expand Down
11 changes: 11 additions & 0 deletions lib/puma/server.rb
Expand Up @@ -1023,5 +1023,16 @@ def self.current
def shutting_down?
@status == :stop || @status == :restart
end

def log_thread_status
Thread.list.each do |thread|
@events.log "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
if thread.backtrace
@events.log thread.backtrace.join("\n")
else
@events.log "<no backtrace available>"
end
end
end
end
end
4 changes: 4 additions & 0 deletions lib/puma/single.rb
Expand Up @@ -113,6 +113,10 @@ def run

@launcher.events.fire_on_booted!

Signal.trap "SIGINFO" do
server.log_thread_status
end

begin
server.run.join
rescue Interrupt
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/integration.rb
Expand Up @@ -97,7 +97,7 @@ def read_body(connection)
end

# gets worker pids from @server output
def get_worker_pids(phase, size = WORKERS)
def get_worker_pids(phase = 0, size = WORKERS)
pids = []
re = /pid: (\d+)\) booted, phase: #{phase}/
while pids.size < size
Expand Down
16 changes: 15 additions & 1 deletion test/test_integration_cluster.rb
Expand Up @@ -8,6 +8,20 @@ def setup
super
end

def test_siginfo_thread_print
skip_unless_signal_exist? :INFO

cli_server("-w #{WORKERS} -q test/rackup/hello.ru")
worker_pids = get_worker_pids
output = []
t = Thread.new { output << @server.readlines }
Process.kill(:INFO, worker_pids.first)
Process.kill(:INT, @server.pid)
t.join

assert_match "Thread TID", output.join
end

def test_usr2_restart
_, new_reply = restart_server_and_listen("-q -w #{WORKERS} test/rackup/hello.ru")
assert_equal "Hello World", new_reply
Expand Down Expand Up @@ -92,7 +106,7 @@ def test_term_worker_clean_exit
pid = cli_server("-w #{WORKERS} test/rackup/hello.ru").pid

# Get the PIDs of the child workers.
worker_pids = get_worker_pids 0
worker_pids = get_worker_pids

# Signal the workers to terminate, and wait for them to die.
Process.kill :TERM, pid
Expand Down
13 changes: 13 additions & 0 deletions test/test_integration_single.rb
Expand Up @@ -84,4 +84,17 @@ def test_int_signal_with_background_thread_in_jruby

assert_raises(Errno::ECONNREFUSED) { TCPSocket.new(HOST, @tcp_port) }
end

def test_siginfo_thread_print
skip_unless_signal_exist? :INFO

cli_server("test/rackup/hello.ru")
output = []
t = Thread.new { output << @server.readlines }
Process.kill(:INFO, @server.pid)
Process.kill(:INT, @server.pid)
t.join

assert_match "Thread TID", output.join
end
end
14 changes: 8 additions & 6 deletions test/test_puma_server.rb
Expand Up @@ -9,7 +9,7 @@ def setup

@app = lambda { |env| [200, {}, [env['rack.url_scheme']]] }

@events = Puma::Events.new STDOUT, STDERR
@events = Puma::Events.strings
@server = Puma::Server.new @app, @events
end

Expand Down Expand Up @@ -280,9 +280,6 @@ def test_GET_with_no_body_has_sane_chunking
end

def test_doesnt_print_backtrace_in_production
@events = Puma::Events.strings
@server = Puma::Server.new @app, @events

@server.app = proc { |e| raise "don't leak me bro" }
@server.leak_stack_on_error = false
@server.add_tcp_listener @host, @port
Expand All @@ -298,7 +295,6 @@ def test_doesnt_print_backtrace_in_production
end

def test_prints_custom_error
@events = Puma::Events.strings
re = lambda { |err| [302, {'Content-Type' => 'text', 'Location' => 'foo.html'}, ['302 found']] }
@server = Puma::Server.new @app, @events, {:lowlevel_error_handler => re}

Expand All @@ -314,7 +310,6 @@ def test_prints_custom_error
end

def test_leh_gets_env_as_well
@events = Puma::Events.strings
re = lambda { |err,env|
env['REQUEST_PATH'] || raise("where is env?")
[302, {'Content-Type' => 'text', 'Location' => 'foo.html'}, ['302 found']]
Expand Down Expand Up @@ -953,4 +948,11 @@ def test_request_body_wait_chunked

assert request_body_wait >= 1000
end

def test_siginfo_prints_thread_traces
@server.log_thread_status
@events.stdout.rewind

assert_match "Thread TID", @events.stdout.read
end
end

0 comments on commit 124c76c

Please sign in to comment.