puma 5.6.9-java → 6.6.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +465 -18
- data/README.md +152 -42
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +12 -4
- data/docs/java_options.md +54 -0
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +4 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +2 -2
- data/docs/stats.md +8 -3
- data/docs/systemd.md +13 -7
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +27 -17
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +137 -19
- data/ext/puma_http11/org/jruby/puma/Http11.java +31 -10
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
- data/ext/puma_http11/puma_http11.c +21 -10
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +60 -55
- data/lib/puma/cli.rb +22 -20
- data/lib/puma/client.rb +93 -30
- data/lib/puma/cluster/worker.rb +27 -17
- data/lib/puma/cluster/worker_handle.rb +8 -6
- data/lib/puma/cluster.rb +121 -47
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +101 -65
- data/lib/puma/const.rb +141 -93
- data/lib/puma/control_cli.rb +19 -15
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +521 -88
- data/lib/puma/error_logger.rb +22 -13
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +0 -15
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +121 -181
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +27 -12
- data/lib/puma/minissl.rb +105 -11
- data/lib/puma/null_io.rb +42 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +368 -169
- data/lib/puma/runner.rb +65 -22
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +161 -102
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +3 -6
- data/lib/puma/thread_pool.rb +71 -21
- data/lib/puma/util.rb +1 -12
- data/lib/puma.rb +9 -10
- data/lib/rack/handler/puma.rb +116 -86
- data/tools/Dockerfile +2 -2
- metadata +17 -12
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
- data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/client.rb
CHANGED
@@ -8,9 +8,9 @@ class IO
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
require_relative 'detect'
|
12
|
+
require_relative 'io_buffer'
|
12
13
|
require 'tempfile'
|
13
|
-
require 'forwardable'
|
14
14
|
|
15
15
|
if Puma::IS_JRUBY
|
16
16
|
# We have to work around some OpenSSL buffer/io-readiness bugs
|
@@ -25,6 +25,9 @@ module Puma
|
|
25
25
|
|
26
26
|
class HttpParserError501 < IOError; end
|
27
27
|
|
28
|
+
#———————————————————————— DO NOT USE — this class is for internal use only ———
|
29
|
+
|
30
|
+
|
28
31
|
# An instance of this class represents a unique request from a client.
|
29
32
|
# For example, this could be a web request from a browser or from CURL.
|
30
33
|
#
|
@@ -38,7 +41,7 @@ module Puma
|
|
38
41
|
# the header and body are fully buffered via the `try_to_finish` method.
|
39
42
|
# They can be used to "time out" a response via the `timeout_at` reader.
|
40
43
|
#
|
41
|
-
class Client
|
44
|
+
class Client # :nodoc:
|
42
45
|
|
43
46
|
# this tests all values but the last, which must be chunked
|
44
47
|
ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
|
@@ -66,17 +69,13 @@ module Puma
|
|
66
69
|
EmptyBody = NullIO.new
|
67
70
|
|
68
71
|
include Puma::Const
|
69
|
-
extend Forwardable
|
70
72
|
|
71
73
|
def initialize(io, env=nil)
|
72
74
|
@io = io
|
73
75
|
@to_io = io.to_io
|
76
|
+
@io_buffer = IOBuffer.new
|
74
77
|
@proto_env = env
|
75
|
-
|
76
|
-
@env = nil
|
77
|
-
else
|
78
|
-
@env = env.dup
|
79
|
-
end
|
78
|
+
@env = env&.dup
|
80
79
|
|
81
80
|
@parser = HttpParser.new
|
82
81
|
@parsed_bytes = 0
|
@@ -94,7 +93,11 @@ module Puma
|
|
94
93
|
@requests_served = 0
|
95
94
|
@hijacked = false
|
96
95
|
|
96
|
+
@http_content_length_limit = nil
|
97
|
+
@http_content_length_limit_exceeded = false
|
98
|
+
|
97
99
|
@peerip = nil
|
100
|
+
@peer_family = nil
|
98
101
|
@listener = nil
|
99
102
|
@remote_addr_header = nil
|
100
103
|
@expect_proxy_proto = false
|
@@ -102,16 +105,22 @@ module Puma
|
|
102
105
|
@body_remain = 0
|
103
106
|
|
104
107
|
@in_last_chunk = false
|
108
|
+
|
109
|
+
# need unfrozen ASCII-8BIT, +'' is UTF-8
|
110
|
+
@read_buffer = String.new # rubocop: disable Performance/UnfreezeString
|
105
111
|
end
|
106
112
|
|
107
113
|
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
|
108
|
-
:tempfile
|
114
|
+
:tempfile, :io_buffer, :http_content_length_limit_exceeded
|
109
115
|
|
110
|
-
attr_writer :peerip
|
116
|
+
attr_writer :peerip, :http_content_length_limit
|
111
117
|
|
112
118
|
attr_accessor :remote_addr_header, :listener
|
113
119
|
|
114
|
-
|
120
|
+
# Remove in Puma 7?
|
121
|
+
def closed?
|
122
|
+
@to_io.closed?
|
123
|
+
end
|
115
124
|
|
116
125
|
# Test to see if io meets a bare minimum of functioning, @to_io needs to be
|
117
126
|
# used for MiniSSL::Socket
|
@@ -147,16 +156,16 @@ module Puma
|
|
147
156
|
|
148
157
|
def reset(fast_check=true)
|
149
158
|
@parser.reset
|
159
|
+
@io_buffer.reset
|
150
160
|
@read_header = true
|
151
161
|
@read_proxy = !!@expect_proxy_proto
|
152
162
|
@env = @proto_env.dup
|
153
|
-
@body = nil
|
154
|
-
@tempfile = nil
|
155
163
|
@parsed_bytes = 0
|
156
164
|
@ready = false
|
157
165
|
@body_remain = 0
|
158
166
|
@peerip = nil if @remote_addr_header
|
159
167
|
@in_last_chunk = false
|
168
|
+
@http_content_length_limit_exceeded = false
|
160
169
|
|
161
170
|
if @buffer
|
162
171
|
return false unless try_to_parse_proxy_protocol
|
@@ -179,11 +188,11 @@ module Puma
|
|
179
188
|
rescue IOError
|
180
189
|
# swallow it
|
181
190
|
end
|
182
|
-
|
183
191
|
end
|
184
192
|
end
|
185
193
|
|
186
194
|
def close
|
195
|
+
tempfile_close
|
187
196
|
begin
|
188
197
|
@io.close
|
189
198
|
rescue IOError, Errno::EBADF
|
@@ -191,6 +200,15 @@ module Puma
|
|
191
200
|
end
|
192
201
|
end
|
193
202
|
|
203
|
+
def tempfile_close
|
204
|
+
tf_path = @tempfile&.path
|
205
|
+
@tempfile&.close
|
206
|
+
File.unlink(tf_path) if tf_path
|
207
|
+
@tempfile = nil
|
208
|
+
@body = nil
|
209
|
+
rescue Errno::ENOENT, IOError
|
210
|
+
end
|
211
|
+
|
194
212
|
# If necessary, read the PROXY protocol from the buffer. Returns
|
195
213
|
# false if more data is needed.
|
196
214
|
def try_to_parse_proxy_protocol
|
@@ -216,8 +234,20 @@ module Puma
|
|
216
234
|
end
|
217
235
|
|
218
236
|
def try_to_finish
|
237
|
+
if env[CONTENT_LENGTH] && above_http_content_limit(env[CONTENT_LENGTH].to_i)
|
238
|
+
@http_content_length_limit_exceeded = true
|
239
|
+
end
|
240
|
+
|
241
|
+
if @http_content_length_limit_exceeded
|
242
|
+
@buffer = nil
|
243
|
+
@body = EmptyBody
|
244
|
+
set_ready
|
245
|
+
return true
|
246
|
+
end
|
247
|
+
|
219
248
|
return read_body if in_data_phase
|
220
249
|
|
250
|
+
data = nil
|
221
251
|
begin
|
222
252
|
data = @io.read_nonblock(CHUNK_SIZE)
|
223
253
|
rescue IO::WaitReadable
|
@@ -245,6 +275,10 @@ module Puma
|
|
245
275
|
|
246
276
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
247
277
|
|
278
|
+
if @parser.finished? && above_http_content_limit(@parser.body.bytesize)
|
279
|
+
@http_content_length_limit_exceeded = true
|
280
|
+
end
|
281
|
+
|
248
282
|
if @parser.finished?
|
249
283
|
return setup_body
|
250
284
|
elsif @parsed_bytes >= MAX_HEADER
|
@@ -282,7 +316,7 @@ module Puma
|
|
282
316
|
return @peerip if @peerip
|
283
317
|
|
284
318
|
if @remote_addr_header
|
285
|
-
hdr = (@env[@remote_addr_header] ||
|
319
|
+
hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
|
286
320
|
@peerip = hdr
|
287
321
|
return hdr
|
288
322
|
end
|
@@ -290,6 +324,16 @@ module Puma
|
|
290
324
|
@peerip ||= @io.peeraddr.last
|
291
325
|
end
|
292
326
|
|
327
|
+
def peer_family
|
328
|
+
return @peer_family if @peer_family
|
329
|
+
|
330
|
+
@peer_family ||= begin
|
331
|
+
@io.local_address.afamily
|
332
|
+
rescue
|
333
|
+
Socket::AF_INET
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
293
337
|
# Returns true if the persistent connection can be closed immediately
|
294
338
|
# without waiting for the configured idle/shutdown timeout.
|
295
339
|
# @version 5.0.0
|
@@ -313,7 +357,7 @@ module Puma
|
|
313
357
|
private
|
314
358
|
|
315
359
|
def setup_body
|
316
|
-
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
360
|
+
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
317
361
|
|
318
362
|
if @env[HTTP_EXPECT] == CONTINUE
|
319
363
|
# TODO allow a hook here to check the headers before
|
@@ -357,7 +401,7 @@ module Puma
|
|
357
401
|
|
358
402
|
if cl
|
359
403
|
# cannot contain characters that are not \d, or be empty
|
360
|
-
if cl
|
404
|
+
if CONTENT_LENGTH_VALUE_INVALID.match?(cl) || cl.empty?
|
361
405
|
raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
|
362
406
|
end
|
363
407
|
else
|
@@ -367,18 +411,33 @@ module Puma
|
|
367
411
|
return true
|
368
412
|
end
|
369
413
|
|
370
|
-
|
414
|
+
content_length = cl.to_i
|
415
|
+
|
416
|
+
remain = content_length - body.bytesize
|
371
417
|
|
372
418
|
if remain <= 0
|
373
|
-
|
374
|
-
|
419
|
+
# Part of the body is a pipelined request OR garbage. We'll deal with that later.
|
420
|
+
if content_length == 0
|
421
|
+
@body = EmptyBody
|
422
|
+
if body.empty?
|
423
|
+
@buffer = nil
|
424
|
+
else
|
425
|
+
@buffer = body
|
426
|
+
end
|
427
|
+
elsif remain == 0
|
428
|
+
@body = StringIO.new body
|
429
|
+
@buffer = nil
|
430
|
+
else
|
431
|
+
@body = StringIO.new(body[0,content_length])
|
432
|
+
@buffer = body[content_length..-1]
|
433
|
+
end
|
375
434
|
set_ready
|
376
435
|
return true
|
377
436
|
end
|
378
437
|
|
379
438
|
if remain > MAX_BODY
|
380
|
-
@body = Tempfile.
|
381
|
-
@body.
|
439
|
+
@body = Tempfile.create(Const::PUMA_TMP_BASE)
|
440
|
+
File.unlink @body.path unless IS_WINDOWS
|
382
441
|
@body.binmode
|
383
442
|
@tempfile = @body
|
384
443
|
else
|
@@ -410,7 +469,7 @@ module Puma
|
|
410
469
|
end
|
411
470
|
|
412
471
|
begin
|
413
|
-
chunk = @io.read_nonblock(want)
|
472
|
+
chunk = @io.read_nonblock(want, @read_buffer)
|
414
473
|
rescue IO::WaitReadable
|
415
474
|
return false
|
416
475
|
rescue SystemCallError, IOError
|
@@ -442,7 +501,7 @@ module Puma
|
|
442
501
|
def read_chunked_body
|
443
502
|
while true
|
444
503
|
begin
|
445
|
-
chunk = @io.read_nonblock(
|
504
|
+
chunk = @io.read_nonblock(CHUNK_SIZE, @read_buffer)
|
446
505
|
rescue IO::WaitReadable
|
447
506
|
return false
|
448
507
|
rescue SystemCallError, IOError
|
@@ -470,8 +529,8 @@ module Puma
|
|
470
529
|
@prev_chunk = ""
|
471
530
|
@excess_cr = 0
|
472
531
|
|
473
|
-
@body = Tempfile.
|
474
|
-
@body.
|
532
|
+
@body = Tempfile.create(Const::PUMA_TMP_BASE)
|
533
|
+
File.unlink @body.path unless IS_WINDOWS
|
475
534
|
@body.binmode
|
476
535
|
@tempfile = @body
|
477
536
|
@chunked_content_length = 0
|
@@ -523,7 +582,7 @@ module Puma
|
|
523
582
|
# Puma doesn't process chunk extensions, but should parse if they're
|
524
583
|
# present, which is the reason for the semicolon regex
|
525
584
|
chunk_hex = line.strip[/\A[^;]+/]
|
526
|
-
if chunk_hex
|
585
|
+
if CHUNK_SIZE_INVALID.match? chunk_hex
|
527
586
|
raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
|
528
587
|
end
|
529
588
|
len = chunk_hex.to_i(16)
|
@@ -591,7 +650,7 @@ module Puma
|
|
591
650
|
@partial_part_left = len - part.size
|
592
651
|
end
|
593
652
|
else
|
594
|
-
if @prev_chunk.size +
|
653
|
+
if @prev_chunk.size + line.size >= MAX_CHUNK_HEADER_SIZE
|
595
654
|
raise HttpParserError, "maximum size of chunk header exceeded"
|
596
655
|
end
|
597
656
|
|
@@ -610,10 +669,14 @@ module Puma
|
|
610
669
|
|
611
670
|
def set_ready
|
612
671
|
if @body_read_start
|
613
|
-
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
672
|
+
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
|
614
673
|
end
|
615
674
|
@requests_served += 1
|
616
675
|
@ready = true
|
617
676
|
end
|
677
|
+
|
678
|
+
def above_http_content_limit(value)
|
679
|
+
@http_content_length_limit&.< value
|
680
|
+
end
|
618
681
|
end
|
619
682
|
end
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -2,27 +2,29 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Puma::Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class is instantiated by the `Puma::Cluster` and represents a single
|
6
9
|
# worker process.
|
7
10
|
#
|
8
11
|
# At the core of this class is running an instance of `Puma::Server` which
|
9
12
|
# gets created via the `start_server` method from the `Puma::Runner` class
|
10
13
|
# that this inherits from.
|
11
|
-
class Worker < Puma::Runner
|
14
|
+
class Worker < Puma::Runner # :nodoc:
|
12
15
|
attr_reader :index, :master
|
13
16
|
|
14
17
|
def initialize(index:, master:, launcher:, pipes:, server: nil)
|
15
|
-
super
|
18
|
+
super(launcher)
|
16
19
|
|
17
20
|
@index = index
|
18
21
|
@master = master
|
19
|
-
@launcher = launcher
|
20
|
-
@options = launcher.options
|
21
22
|
@check_pipe = pipes[:check_pipe]
|
22
23
|
@worker_write = pipes[:worker_write]
|
23
24
|
@fork_pipe = pipes[:fork_pipe]
|
24
25
|
@wakeup = pipes[:wakeup]
|
25
26
|
@server = server
|
27
|
+
@hook_data = {}
|
26
28
|
end
|
27
29
|
|
28
30
|
def run
|
@@ -52,13 +54,14 @@ module Puma
|
|
52
54
|
|
53
55
|
# Invoke any worker boot hooks so they can get
|
54
56
|
# things in shape before booting the app.
|
55
|
-
@
|
57
|
+
@config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
|
56
58
|
|
57
59
|
begin
|
58
60
|
server = @server ||= start_server
|
59
61
|
rescue Exception => e
|
60
62
|
log "! Unable to start worker"
|
61
|
-
log e
|
63
|
+
log e
|
64
|
+
log e.backtrace.join("\n ")
|
62
65
|
exit 1
|
63
66
|
end
|
64
67
|
|
@@ -83,28 +86,29 @@ module Puma
|
|
83
86
|
if restart_server.length > 0
|
84
87
|
restart_server.clear
|
85
88
|
server.begin_restart(true)
|
86
|
-
@
|
87
|
-
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
89
|
+
@config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
|
88
90
|
end
|
91
|
+
elsif idx == -2 # refork cycle is done
|
92
|
+
@config.run_hooks(:after_refork, nil, @log_writer, @hook_data)
|
89
93
|
elsif idx == 0 # restart server
|
90
94
|
restart_server << true << false
|
91
95
|
else # fork worker
|
92
96
|
worker_pids << pid = spawn_worker(idx)
|
93
|
-
@worker_write << "
|
97
|
+
@worker_write << "#{PIPE_FORK}#{pid}:#{idx}\n" rescue nil
|
94
98
|
end
|
95
99
|
end
|
96
100
|
end
|
97
101
|
end
|
98
102
|
|
99
103
|
Signal.trap "SIGTERM" do
|
100
|
-
@worker_write << "
|
104
|
+
@worker_write << "#{PIPE_EXTERNAL_TERM}#{Process.pid}\n" rescue nil
|
101
105
|
restart_server.clear
|
102
106
|
server.stop
|
103
107
|
restart_server << false
|
104
108
|
end
|
105
109
|
|
106
110
|
begin
|
107
|
-
@worker_write << "
|
111
|
+
@worker_write << "#{PIPE_BOOT}#{Process.pid}:#{index}\n"
|
108
112
|
rescue SystemCallError, IOError
|
109
113
|
Puma::Util.purge_interrupt_queue
|
110
114
|
STDERR.puts "Master seems to have exited, exiting."
|
@@ -113,9 +117,14 @@ module Puma
|
|
113
117
|
|
114
118
|
while restart_server.pop
|
115
119
|
server_thread = server.run
|
120
|
+
|
121
|
+
if @log_writer.debug? && index == 0
|
122
|
+
debug_loaded_extensions "Loaded Extensions - worker 0:"
|
123
|
+
end
|
124
|
+
|
116
125
|
stat_thread ||= Thread.new(@worker_write) do |io|
|
117
126
|
Puma.set_thread_name "stat pld"
|
118
|
-
base_payload = "
|
127
|
+
base_payload = "#{PIPE_PING}#{Process.pid}"
|
119
128
|
|
120
129
|
while true
|
121
130
|
begin
|
@@ -124,7 +133,8 @@ module Puma
|
|
124
133
|
t = server.pool_capacity || 0
|
125
134
|
m = server.max_threads || 0
|
126
135
|
rc = server.requests_count || 0
|
127
|
-
|
136
|
+
bt = server.busy_threads || 0
|
137
|
+
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads":#{m}, "requests_count":#{rc}, "busy_threads":#{bt} }\n!
|
128
138
|
io << payload
|
129
139
|
rescue IOError
|
130
140
|
Puma::Util.purge_interrupt_queue
|
@@ -138,16 +148,16 @@ module Puma
|
|
138
148
|
|
139
149
|
# Invoke any worker shutdown hooks so they can prevent the worker
|
140
150
|
# exiting until any background operations are completed
|
141
|
-
@
|
151
|
+
@config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
|
142
152
|
ensure
|
143
|
-
@worker_write << "
|
153
|
+
@worker_write << "#{PIPE_TERM}#{Process.pid}\n" rescue nil
|
144
154
|
@worker_write.close
|
145
155
|
end
|
146
156
|
|
147
157
|
private
|
148
158
|
|
149
159
|
def spawn_worker(idx)
|
150
|
-
@
|
160
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
|
151
161
|
|
152
162
|
pid = fork do
|
153
163
|
new_worker = Worker.new index: idx,
|
@@ -165,7 +175,7 @@ module Puma
|
|
165
175
|
exit! 1
|
166
176
|
end
|
167
177
|
|
168
|
-
@
|
178
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
|
169
179
|
pid
|
170
180
|
end
|
171
181
|
end
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class represents a worker process from the perspective of the puma
|
6
9
|
# master process. It contains information about the process and its health
|
7
10
|
# and it exposes methods to control the process via IPC. It does not
|
8
11
|
# include the actual logic executed by the worker process itself. For that,
|
9
12
|
# see Puma::Cluster::Worker.
|
10
|
-
class WorkerHandle
|
13
|
+
class WorkerHandle # :nodoc:
|
11
14
|
def initialize(idx, pid, phase, options)
|
12
15
|
@index = idx
|
13
16
|
@pid = pid
|
@@ -48,13 +51,12 @@ module Puma
|
|
48
51
|
@term
|
49
52
|
end
|
50
53
|
|
54
|
+
STATUS_PATTERN = /{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads":(?<max_threads>\d*), "requests_count":(?<requests_count>\d*), "busy_threads":(?<busy_threads>\d*) }/
|
55
|
+
private_constant :STATUS_PATTERN
|
56
|
+
|
51
57
|
def ping!(status)
|
52
58
|
@last_checkin = Time.now
|
53
|
-
|
54
|
-
@last_status = captures.names.inject({}) do |hash, key|
|
55
|
-
hash[key.to_sym] = captures[key].to_i
|
56
|
-
hash
|
57
|
-
end
|
59
|
+
@last_status = status.match(STATUS_PATTERN).named_captures.map { |c_name, c| [c_name.to_sym, c.to_i] }.to_h
|
58
60
|
end
|
59
61
|
|
60
62
|
# @see Puma::Cluster#check_workers
|