Skip to content

Commit

Permalink
Instrument requests count (#2106)
Browse files Browse the repository at this point in the history
* Instrument requests count

* Fix existing tests

* Add history

* add new test
  • Loading branch information
ylecuyer committed Feb 11, 2020
1 parent 6f59df8 commit a391634
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 7 deletions.
1 change: 1 addition & 0 deletions History.md
Expand Up @@ -5,6 +5,7 @@
* Configuration: `environment` is read from `RAILS_ENV`, if `RACK_ENV` can't be found (#2022)
* `Puma.stats` now returns a Hash instead of a JSON string (#2086)
* `GC.compact` is called before fork if available (#2093)
* Add `requests_count` to workers stats. (#2106)

* Bugfixes
* Your bugfix goes here (#Github Number)
Expand Down
5 changes: 3 additions & 2 deletions lib/puma/cluster.rb
Expand Up @@ -94,7 +94,7 @@ def term?

def ping!(status)
@last_checkin = Time.now
captures = status.match(/{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads": (?<max_threads>\d*) }/)
captures = status.match(/{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads": (?<max_threads>\d*), "requests_count": (?<requests_count>\d*) }/)
@last_status = captures.names.inject({}) do |hash, key|
hash[key.to_sym] = captures[key].to_i
hash
Expand Down Expand Up @@ -296,7 +296,8 @@ def worker(index, master)
r = server.running || 0
t = server.pool_capacity || 0
m = server.max_threads || 0
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m} }\n!
rc = server.requests_count || 0
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
io << payload
rescue IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
Expand Down
5 changes: 5 additions & 0 deletions lib/puma/server.rb
Expand Up @@ -36,6 +36,7 @@ class Server

attr_reader :thread
attr_reader :events
attr_reader :requests_count
attr_accessor :app

attr_accessor :min_threads
Expand Down Expand Up @@ -85,6 +86,8 @@ def initialize(app, events=Events.stdio, options={})
@mode = :http

@precheck_closing = true

@requests_count = 0
end

attr_accessor :binder, :leak_stack_on_error, :early_hints
Expand Down Expand Up @@ -626,6 +629,8 @@ def default_server_port(env)
#
# Finally, it'll return +true+ on keep-alive connections.
def handle_request(req, lines)
@requests_count +=1

env = req.env
client = req.io

Expand Down
1 change: 1 addition & 0 deletions lib/puma/single.rb
Expand Up @@ -20,6 +20,7 @@ def stats
running: @server.running || 0,
pool_capacity: @server.pool_capacity || 0,
max_threads: @server.max_threads || 0,
requests_count: @server.requests_count || 0,
}
end

Expand Down
52 changes: 47 additions & 5 deletions test/test_cli.rb
Expand Up @@ -57,7 +57,7 @@ def test_control_for_tcp
body = s.read
s.close

assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16}/, body.split(/\r?\n/).last)
assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16,"requests_count":0}/, body.split(/\r?\n/).last)

ensure
cli.launcher.stop
Expand Down Expand Up @@ -91,9 +91,9 @@ def test_control_for_ssl
body = http.request(req).body
end

expected_stats = /{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16}/
expected_stats = /{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16,"requests_count":0}/
assert_match(expected_stats, body.split(/\r?\n/).last)
assert_equal([:started_at, :backlog, :running, :pool_capacity, :max_threads], Puma.stats.keys)
assert_equal([:started_at, :backlog, :running, :pool_capacity, :max_threads, :requests_count], Puma.stats.keys)

ensure
cli.launcher.stop
Expand Down Expand Up @@ -136,7 +136,7 @@ def test_control_clustered
body = s.read
s.close

assert_match(/\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","workers":2,"phase":0,"booted_workers":2,"old_workers":0,"worker_status":\[\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","pid":\d+,"index":0,"phase":0,"booted":true,"last_checkin":"[^"]+","last_status":\{"backlog":0,"running":2,"pool_capacity":2,"max_threads":2\}\},\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","pid":\d+,"index":1,"phase":0,"booted":true,"last_checkin":"[^"]+","last_status":\{"backlog":0,"running":2,"pool_capacity":2,"max_threads":2\}\}\]\}/, body.split("\r\n").last)
assert_match(/\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","workers":2,"phase":0,"booted_workers":2,"old_workers":0,"worker_status":\[\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","pid":\d+,"index":0,"phase":0,"booted":true,"last_checkin":"[^"]+","last_status":\{"backlog":0,"running":2,"pool_capacity":2,"max_threads":2,"requests_count":0\}\},\{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","pid":\d+,"index":1,"phase":0,"booted":true,"last_checkin":"[^"]+","last_status":\{"backlog":0,"running":2,"pool_capacity":2,"max_threads":2,"requests_count":0\}\}\]\}/, body.split("\r\n").last)
ensure
if UNIX_SKT_EXIST && HAS_FORK
cli.launcher.stop
Expand Down Expand Up @@ -171,7 +171,7 @@ def test_control
body = s.read
s.close

assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16}/, body.split("\r\n").last)
assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":0,"running":0,"pool_capacity":16,"max_threads":16,"requests_count":0}/, body.split("\r\n").last)
ensure
if UNIX_SKT_EXIST
cli.launcher.stop
Expand Down Expand Up @@ -202,6 +202,48 @@ def test_control_stop
t.join if UNIX_SKT_EXIST
end

def test_control_requests_count
tcp = UniquePort.call
cntl = UniquePort.call
url = "tcp://127.0.0.1:#{cntl}/"

cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:#{tcp}",
"--control-url", url,
"--control-token", "",
"test/rackup/lobster.ru"], @events

t = Thread.new do
cli.run
end

wait_booted

s = TCPSocket.new "127.0.0.1", cntl
s << "GET /stats HTTP/1.0\r\n\r\n"
body = s.read
s.close

assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":\d+,"running":\d+,"pool_capacity":\d+,"max_threads":\d+,"requests_count":0}/, body.split(/\r?\n/).last)

# send real requests to server
3.times do
s = TCPSocket.new "127.0.0.1", tcp
s << "GET / HTTP/1.0\r\n\r\n"
body = s.read
s.close
end

s = TCPSocket.new "127.0.0.1", cntl
s << "GET /stats HTTP/1.0\r\n\r\n"
body = s.read
s.close

assert_match(/{"started_at":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z","backlog":\d+,"running":\d+,"pool_capacity":\d+,"max_threads":\d+,"requests_count":3}/, body.split(/\r?\n/).last)
ensure
cli.launcher.stop
t.join
end

def test_control_thread_backtraces
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
url = "unix://#{@tmp_path}"
Expand Down
8 changes: 8 additions & 0 deletions test/test_web_server.rb
Expand Up @@ -38,6 +38,14 @@ def test_simple_server
assert @tester.ran_test, "Handler didn't really run"
end

def test_requests_count
assert_equal @server.requests_count, 0
3.times do
hit(["http://127.0.0.1:#{@server.connected_port}/test"])
end
assert_equal @server.requests_count, 3
end

def test_trickle_attack
socket = do_test(VALID_REQUEST, 3)
assert_match "hello", socket.read
Expand Down

0 comments on commit a391634

Please sign in to comment.