puma 5.3.2 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +284 -11
- data/LICENSE +0 -0
- data/README.md +61 -16
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +49 -16
- data/docs/compile_options.md +38 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +1 -3
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +0 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +6 -6
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +64 -67
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +44 -13
- data/ext/puma_http11/http11_parser.c +24 -11
- 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 +3 -3
- data/ext/puma_http11/mini_ssl.c +122 -23
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +9 -6
- data/lib/puma/binder.rb +81 -42
- data/lib/puma/cli.rb +23 -19
- data/lib/puma/client.rb +124 -30
- data/lib/puma/cluster/worker.rb +21 -29
- data/lib/puma/cluster/worker_handle.rb +8 -1
- data/lib/puma/cluster.rb +57 -48
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +74 -55
- data/lib/puma/const.rb +21 -24
- data/lib/puma/control_cli.rb +22 -19
- data/lib/puma/detect.rb +10 -2
- data/lib/puma/dsl.rb +196 -57
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +29 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +108 -154
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +29 -16
- data/lib/puma/minissl.rb +115 -38
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/rack/builder.rb +5 -5
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +3 -3
- data/lib/puma/request.rb +293 -153
- data/lib/puma/runner.rb +63 -28
- data/lib/puma/server.rb +83 -88
- data/lib/puma/single.rb +10 -10
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +22 -17
- data/lib/puma/util.rb +20 -15
- data/lib/puma.rb +12 -9
- data/lib/rack/handler/puma.rb +9 -9
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +13 -9
- data/lib/puma/queue_close.rb +0 -26
data/lib/puma/client.rb
CHANGED
@@ -8,7 +8,7 @@ class IO
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
require_relative 'detect'
|
12
12
|
require 'tempfile'
|
13
13
|
require 'forwardable'
|
14
14
|
|
@@ -23,6 +23,11 @@ module Puma
|
|
23
23
|
|
24
24
|
class ConnectionError < RuntimeError; end
|
25
25
|
|
26
|
+
class HttpParserError501 < IOError; end
|
27
|
+
|
28
|
+
#———————————————————————— DO NOT USE — this class is for internal use only ———
|
29
|
+
|
30
|
+
|
26
31
|
# An instance of this class represents a unique request from a client.
|
27
32
|
# For example, this could be a web request from a browser or from CURL.
|
28
33
|
#
|
@@ -35,7 +40,21 @@ module Puma
|
|
35
40
|
# Instances of this class are responsible for knowing if
|
36
41
|
# the header and body are fully buffered via the `try_to_finish` method.
|
37
42
|
# They can be used to "time out" a response via the `timeout_at` reader.
|
38
|
-
|
43
|
+
#
|
44
|
+
class Client # :nodoc:
|
45
|
+
|
46
|
+
# this tests all values but the last, which must be chunked
|
47
|
+
ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
|
48
|
+
|
49
|
+
# chunked body validation
|
50
|
+
CHUNK_SIZE_INVALID = /[^\h]/.freeze
|
51
|
+
CHUNK_VALID_ENDING = "\r\n".freeze
|
52
|
+
|
53
|
+
# Content-Length header value validation
|
54
|
+
CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
|
55
|
+
|
56
|
+
TE_ERR_MSG = 'Invalid Transfer-Encoding'
|
57
|
+
|
39
58
|
# The object used for a request with no body. All requests with
|
40
59
|
# no body share this one object since it has no state.
|
41
60
|
EmptyBody = NullIO.new
|
@@ -47,15 +66,12 @@ module Puma
|
|
47
66
|
@io = io
|
48
67
|
@to_io = io.to_io
|
49
68
|
@proto_env = env
|
50
|
-
|
51
|
-
@env = nil
|
52
|
-
else
|
53
|
-
@env = env.dup
|
54
|
-
end
|
69
|
+
@env = env ? env.dup : nil
|
55
70
|
|
56
71
|
@parser = HttpParser.new
|
57
72
|
@parsed_bytes = 0
|
58
73
|
@read_header = true
|
74
|
+
@read_proxy = false
|
59
75
|
@ready = false
|
60
76
|
|
61
77
|
@body = nil
|
@@ -69,8 +85,10 @@ module Puma
|
|
69
85
|
@hijacked = false
|
70
86
|
|
71
87
|
@peerip = nil
|
88
|
+
@peer_family = nil
|
72
89
|
@listener = nil
|
73
90
|
@remote_addr_header = nil
|
91
|
+
@expect_proxy_proto = false
|
74
92
|
|
75
93
|
@body_remain = 0
|
76
94
|
|
@@ -106,7 +124,7 @@ module Puma
|
|
106
124
|
|
107
125
|
# @!attribute [r] in_data_phase
|
108
126
|
def in_data_phase
|
109
|
-
|
127
|
+
!(@read_header || @read_proxy)
|
110
128
|
end
|
111
129
|
|
112
130
|
def set_timeout(val)
|
@@ -121,6 +139,7 @@ module Puma
|
|
121
139
|
def reset(fast_check=true)
|
122
140
|
@parser.reset
|
123
141
|
@read_header = true
|
142
|
+
@read_proxy = !!@expect_proxy_proto
|
124
143
|
@env = @proto_env.dup
|
125
144
|
@body = nil
|
126
145
|
@tempfile = nil
|
@@ -131,6 +150,8 @@ module Puma
|
|
131
150
|
@in_last_chunk = false
|
132
151
|
|
133
152
|
if @buffer
|
153
|
+
return false unless try_to_parse_proxy_protocol
|
154
|
+
|
134
155
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
135
156
|
|
136
157
|
if @parser.finished?
|
@@ -143,8 +164,7 @@ module Puma
|
|
143
164
|
return false
|
144
165
|
else
|
145
166
|
begin
|
146
|
-
if fast_check &&
|
147
|
-
IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
|
167
|
+
if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
|
148
168
|
return try_to_finish
|
149
169
|
end
|
150
170
|
rescue IOError
|
@@ -157,13 +177,37 @@ module Puma
|
|
157
177
|
def close
|
158
178
|
begin
|
159
179
|
@io.close
|
160
|
-
rescue IOError
|
161
|
-
|
180
|
+
rescue IOError, Errno::EBADF
|
181
|
+
Puma::Util.purge_interrupt_queue
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# If necessary, read the PROXY protocol from the buffer. Returns
|
186
|
+
# false if more data is needed.
|
187
|
+
def try_to_parse_proxy_protocol
|
188
|
+
if @read_proxy
|
189
|
+
if @expect_proxy_proto == :v1
|
190
|
+
if @buffer.include? "\r\n"
|
191
|
+
if md = PROXY_PROTOCOL_V1_REGEX.match(@buffer)
|
192
|
+
if md[1]
|
193
|
+
@peerip = md[1].split(" ")[0]
|
194
|
+
end
|
195
|
+
@buffer = md.post_match
|
196
|
+
end
|
197
|
+
# if the buffer has a \r\n but doesn't have a PROXY protocol
|
198
|
+
# request, this is just HTTP from a non-PROXY client; move on
|
199
|
+
@read_proxy = false
|
200
|
+
return @buffer.size > 0
|
201
|
+
else
|
202
|
+
return false
|
203
|
+
end
|
204
|
+
end
|
162
205
|
end
|
206
|
+
true
|
163
207
|
end
|
164
208
|
|
165
209
|
def try_to_finish
|
166
|
-
return read_body
|
210
|
+
return read_body if in_data_phase
|
167
211
|
|
168
212
|
begin
|
169
213
|
data = @io.read_nonblock(CHUNK_SIZE)
|
@@ -188,6 +232,8 @@ module Puma
|
|
188
232
|
@buffer = data
|
189
233
|
end
|
190
234
|
|
235
|
+
return false unless try_to_parse_proxy_protocol
|
236
|
+
|
191
237
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
192
238
|
|
193
239
|
if @parser.finished?
|
@@ -202,13 +248,13 @@ module Puma
|
|
202
248
|
|
203
249
|
def eagerly_finish
|
204
250
|
return true if @ready
|
205
|
-
return false unless
|
251
|
+
return false unless @to_io.wait_readable(0)
|
206
252
|
try_to_finish
|
207
253
|
end
|
208
254
|
|
209
255
|
def finish(timeout)
|
210
256
|
return if @ready
|
211
|
-
|
257
|
+
@to_io.wait_readable(timeout) || timeout! until try_to_finish
|
212
258
|
end
|
213
259
|
|
214
260
|
def timeout!
|
@@ -227,7 +273,7 @@ module Puma
|
|
227
273
|
return @peerip if @peerip
|
228
274
|
|
229
275
|
if @remote_addr_header
|
230
|
-
hdr = (@env[@remote_addr_header] ||
|
276
|
+
hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
|
231
277
|
@peerip = hdr
|
232
278
|
return hdr
|
233
279
|
end
|
@@ -235,6 +281,16 @@ module Puma
|
|
235
281
|
@peerip ||= @io.peeraddr.last
|
236
282
|
end
|
237
283
|
|
284
|
+
def peer_family
|
285
|
+
return @peer_family if @peer_family
|
286
|
+
|
287
|
+
@peer_family ||= begin
|
288
|
+
@io.local_address.afamily
|
289
|
+
rescue
|
290
|
+
Socket::AF_INET
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
238
294
|
# Returns true if the persistent connection can be closed immediately
|
239
295
|
# without waiting for the configured idle/shutdown timeout.
|
240
296
|
# @version 5.0.0
|
@@ -244,10 +300,21 @@ module Puma
|
|
244
300
|
@parsed_bytes == 0
|
245
301
|
end
|
246
302
|
|
303
|
+
def expect_proxy_proto=(val)
|
304
|
+
if val
|
305
|
+
if @read_header
|
306
|
+
@read_proxy = true
|
307
|
+
end
|
308
|
+
else
|
309
|
+
@read_proxy = false
|
310
|
+
end
|
311
|
+
@expect_proxy_proto = val
|
312
|
+
end
|
313
|
+
|
247
314
|
private
|
248
315
|
|
249
316
|
def setup_body
|
250
|
-
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
317
|
+
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
251
318
|
|
252
319
|
if @env[HTTP_EXPECT] == CONTINUE
|
253
320
|
# TODO allow a hook here to check the headers before
|
@@ -261,16 +328,27 @@ module Puma
|
|
261
328
|
body = @parser.body
|
262
329
|
|
263
330
|
te = @env[TRANSFER_ENCODING2]
|
264
|
-
|
265
331
|
if te
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
332
|
+
te_lwr = te.downcase
|
333
|
+
if te.include? ','
|
334
|
+
te_ary = te_lwr.split ','
|
335
|
+
te_count = te_ary.count CHUNKED
|
336
|
+
te_valid = te_ary[0..-2].all? { |e| ALLOWED_TRANSFER_ENCODING.include? e }
|
337
|
+
if te_ary.last == CHUNKED && te_count == 1 && te_valid
|
338
|
+
@env.delete TRANSFER_ENCODING2
|
339
|
+
return setup_chunked_body body
|
340
|
+
elsif te_count >= 1
|
341
|
+
raise HttpParserError , "#{TE_ERR_MSG}, multiple chunked: '#{te}'"
|
342
|
+
elsif !te_valid
|
343
|
+
raise HttpParserError501, "#{TE_ERR_MSG}, unknown value: '#{te}'"
|
271
344
|
end
|
272
|
-
elsif
|
273
|
-
|
345
|
+
elsif te_lwr == CHUNKED
|
346
|
+
@env.delete TRANSFER_ENCODING2
|
347
|
+
return setup_chunked_body body
|
348
|
+
elsif ALLOWED_TRANSFER_ENCODING.include? te_lwr
|
349
|
+
raise HttpParserError , "#{TE_ERR_MSG}, single value must be chunked: '#{te}'"
|
350
|
+
else
|
351
|
+
raise HttpParserError501 , "#{TE_ERR_MSG}, unknown value: '#{te}'"
|
274
352
|
end
|
275
353
|
end
|
276
354
|
|
@@ -278,7 +356,12 @@ module Puma
|
|
278
356
|
|
279
357
|
cl = @env[CONTENT_LENGTH]
|
280
358
|
|
281
|
-
|
359
|
+
if cl
|
360
|
+
# cannot contain characters that are not \d
|
361
|
+
if CONTENT_LENGTH_VALUE_INVALID.match? cl
|
362
|
+
raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
|
363
|
+
end
|
364
|
+
else
|
282
365
|
@buffer = body.empty? ? nil : body
|
283
366
|
@body = EmptyBody
|
284
367
|
set_ready
|
@@ -309,7 +392,7 @@ module Puma
|
|
309
392
|
|
310
393
|
@body_remain = remain
|
311
394
|
|
312
|
-
|
395
|
+
false
|
313
396
|
end
|
314
397
|
|
315
398
|
def read_body
|
@@ -437,7 +520,13 @@ module Puma
|
|
437
520
|
while !io.eof?
|
438
521
|
line = io.gets
|
439
522
|
if line.end_with?("\r\n")
|
440
|
-
|
523
|
+
# Puma doesn't process chunk extensions, but should parse if they're
|
524
|
+
# present, which is the reason for the semicolon regex
|
525
|
+
chunk_hex = line.strip[/\A[^;]+/]
|
526
|
+
if CHUNK_SIZE_INVALID.match? chunk_hex
|
527
|
+
raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
|
528
|
+
end
|
529
|
+
len = chunk_hex.to_i(16)
|
441
530
|
if len == 0
|
442
531
|
@in_last_chunk = true
|
443
532
|
@body.rewind
|
@@ -468,7 +557,12 @@ module Puma
|
|
468
557
|
|
469
558
|
case
|
470
559
|
when got == len
|
471
|
-
|
560
|
+
# proper chunked segment must end with "\r\n"
|
561
|
+
if part.end_with? CHUNK_VALID_ENDING
|
562
|
+
write_chunk(part[0..-3]) # to skip the ending \r\n
|
563
|
+
else
|
564
|
+
raise HttpParserError, "Chunk size mismatch"
|
565
|
+
end
|
472
566
|
when got <= len - 2
|
473
567
|
write_chunk(part)
|
474
568
|
@partial_part_left = len - part.size
|
@@ -492,7 +586,7 @@ module Puma
|
|
492
586
|
|
493
587
|
def set_ready
|
494
588
|
if @body_read_start
|
495
|
-
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
589
|
+
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
|
496
590
|
end
|
497
591
|
@requests_served += 1
|
498
592
|
@ready = true
|
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
|
@@ -33,9 +35,9 @@ module Puma
|
|
33
35
|
Signal.trap "SIGINT", "IGNORE"
|
34
36
|
Signal.trap "SIGCHLD", "DEFAULT"
|
35
37
|
|
36
|
-
|
37
|
-
Puma.set_thread_name "
|
38
|
-
|
38
|
+
Thread.new do
|
39
|
+
Puma.set_thread_name "wrkr check"
|
40
|
+
@check_pipe.wait_readable
|
39
41
|
log "! Detected parent died, dying"
|
40
42
|
exit! 1
|
41
43
|
end
|
@@ -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
|
|
@@ -76,15 +79,14 @@ module Puma
|
|
76
79
|
end
|
77
80
|
|
78
81
|
Thread.new do
|
79
|
-
Puma.set_thread_name "
|
82
|
+
Puma.set_thread_name "wrkr fork"
|
80
83
|
while (idx = @fork_pipe.gets)
|
81
84
|
idx = idx.to_i
|
82
85
|
if idx == -1 # stop server
|
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
|
89
91
|
elsif idx == 0 # restart server
|
90
92
|
restart_server << true << false
|
@@ -106,7 +108,7 @@ module Puma
|
|
106
108
|
begin
|
107
109
|
@worker_write << "b#{Process.pid}:#{index}\n"
|
108
110
|
rescue SystemCallError, IOError
|
109
|
-
|
111
|
+
Puma::Util.purge_interrupt_queue
|
110
112
|
STDERR.puts "Master seems to have exited, exiting."
|
111
113
|
return
|
112
114
|
end
|
@@ -114,7 +116,7 @@ module Puma
|
|
114
116
|
while restart_server.pop
|
115
117
|
server_thread = server.run
|
116
118
|
stat_thread ||= Thread.new(@worker_write) do |io|
|
117
|
-
Puma.set_thread_name "stat
|
119
|
+
Puma.set_thread_name "stat pld"
|
118
120
|
base_payload = "p#{Process.pid}"
|
119
121
|
|
120
122
|
while true
|
@@ -127,10 +129,10 @@ module Puma
|
|
127
129
|
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
|
128
130
|
io << payload
|
129
131
|
rescue IOError
|
130
|
-
|
132
|
+
Puma::Util.purge_interrupt_queue
|
131
133
|
break
|
132
134
|
end
|
133
|
-
sleep
|
135
|
+
sleep @options[:worker_check_interval]
|
134
136
|
end
|
135
137
|
end
|
136
138
|
server_thread.join
|
@@ -138,7 +140,7 @@ module Puma
|
|
138
140
|
|
139
141
|
# Invoke any worker shutdown hooks so they can prevent the worker
|
140
142
|
# exiting until any background operations are completed
|
141
|
-
@
|
143
|
+
@config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
|
142
144
|
ensure
|
143
145
|
@worker_write << "t#{Process.pid}\n" rescue nil
|
144
146
|
@worker_write.close
|
@@ -147,7 +149,7 @@ module Puma
|
|
147
149
|
private
|
148
150
|
|
149
151
|
def spawn_worker(idx)
|
150
|
-
@
|
152
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
|
151
153
|
|
152
154
|
pid = fork do
|
153
155
|
new_worker = Worker.new index: idx,
|
@@ -165,19 +167,9 @@ module Puma
|
|
165
167
|
exit! 1
|
166
168
|
end
|
167
169
|
|
168
|
-
@
|
170
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
|
169
171
|
pid
|
170
172
|
end
|
171
|
-
|
172
|
-
def wakeup!
|
173
|
-
return unless @wakeup
|
174
|
-
|
175
|
-
begin
|
176
|
-
@wakeup.write "!" unless @wakeup.closed?
|
177
|
-
rescue SystemCallError, IOError
|
178
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
179
|
-
end
|
180
|
-
end
|
181
173
|
end
|
182
174
|
end
|
183
175
|
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
|
@@ -40,6 +43,10 @@ module Puma
|
|
40
43
|
@stage = :booted
|
41
44
|
end
|
42
45
|
|
46
|
+
def term!
|
47
|
+
@term = true
|
48
|
+
end
|
49
|
+
|
43
50
|
def term?
|
44
51
|
@term
|
45
52
|
end
|