puma 5.6.4 → 6.0.2
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 +163 -3
- data/README.md +21 -17
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- 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 +18 -10
- 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 +63 -24
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +166 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +6 -3
- data/lib/puma/binder.rb +37 -43
- data/lib/puma/cli.rb +11 -17
- data/lib/puma/client.rb +26 -13
- data/lib/puma/cluster/worker.rb +13 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +31 -30
- data/lib/puma/configuration.rb +74 -58
- data/lib/puma/const.rb +76 -88
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +97 -49
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +107 -156
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +23 -12
- data/lib/puma/minissl.rb +91 -15
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/rack/builder.rb +4 -4
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +4 -4
- data/lib/puma/request.rb +334 -162
- data/lib/puma/runner.rb +45 -20
- data/lib/puma/server.rb +55 -69
- data/lib/puma/single.rb +11 -11
- data/lib/puma/state_file.rb +2 -4
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +16 -16
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +9 -9
- metadata +7 -3
- data/lib/puma/queue_close.rb +0 -26
data/lib/puma/binder.rb
CHANGED
@@ -3,24 +3,15 @@
|
|
3
3
|
require 'uri'
|
4
4
|
require 'socket'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require_relative 'const'
|
7
|
+
require_relative 'util'
|
8
|
+
require_relative 'configuration'
|
9
9
|
|
10
10
|
module Puma
|
11
11
|
|
12
12
|
if HAS_SSL
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Odd bug in 'pure Ruby' nio4r version 2.5.2, which installs with Ruby 2.3.
|
17
|
-
# NIO doesn't create any OpenSSL objects, but it rescues an OpenSSL error.
|
18
|
-
# The bug was that it did not require openssl.
|
19
|
-
# @todo remove when Ruby 2.3 support is dropped
|
20
|
-
#
|
21
|
-
if windows? && RbConfig::CONFIG['ruby_version'] == '2.3.0'
|
22
|
-
require 'openssl'
|
23
|
-
end
|
13
|
+
require_relative 'minissl'
|
14
|
+
require_relative 'minissl/context_builder'
|
24
15
|
end
|
25
16
|
|
26
17
|
class Binder
|
@@ -28,8 +19,8 @@ module Puma
|
|
28
19
|
|
29
20
|
RACK_VERSION = [1,6].freeze
|
30
21
|
|
31
|
-
def initialize(
|
32
|
-
@
|
22
|
+
def initialize(log_writer, conf = Configuration.new)
|
23
|
+
@log_writer = log_writer
|
33
24
|
@conf = conf
|
34
25
|
@listeners = []
|
35
26
|
@inherited_fds = {}
|
@@ -38,7 +29,7 @@ module Puma
|
|
38
29
|
|
39
30
|
@proto_env = {
|
40
31
|
"rack.version".freeze => RACK_VERSION,
|
41
|
-
"rack.errors".freeze =>
|
32
|
+
"rack.errors".freeze => log_writer.stderr,
|
42
33
|
"rack.multithread".freeze => conf.options[:max_threads] > 1,
|
43
34
|
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
44
35
|
"rack.run_once".freeze => false,
|
@@ -51,7 +42,6 @@ module Puma
|
|
51
42
|
# infer properly.
|
52
43
|
|
53
44
|
"QUERY_STRING".freeze => "",
|
54
|
-
SERVER_PROTOCOL => HTTP_11,
|
55
45
|
SERVER_SOFTWARE => PUMA_SERVER_STRING,
|
56
46
|
GATEWAY_INTERFACE => CGI_VER
|
57
47
|
}
|
@@ -80,7 +70,7 @@ module Puma
|
|
80
70
|
# @!attribute [r] connected_ports
|
81
71
|
# @version 5.0.0
|
82
72
|
def connected_ports
|
83
|
-
ios.map { |io| io.addr[1] }.uniq
|
73
|
+
t = ios.map { |io| io.addr[1] }; t.uniq!; t
|
84
74
|
end
|
85
75
|
|
86
76
|
# @version 5.0.0
|
@@ -98,7 +88,7 @@ module Puma
|
|
98
88
|
# @version 5.0.0
|
99
89
|
#
|
100
90
|
def create_activated_fds(env_hash)
|
101
|
-
@
|
91
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
102
92
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
103
93
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
104
94
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
@@ -106,11 +96,11 @@ module Puma
|
|
106
96
|
[:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
|
107
97
|
rescue ArgumentError # Try to parse as a port/ip
|
108
98
|
port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
|
109
|
-
addr = "[#{addr}]" if addr
|
99
|
+
addr = "[#{addr}]" if addr&.include? ':'
|
110
100
|
[:tcp, addr, port]
|
111
101
|
end
|
112
102
|
@activated_sockets[key] = sock
|
113
|
-
@
|
103
|
+
@log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
|
114
104
|
end
|
115
105
|
["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
|
116
106
|
end
|
@@ -152,17 +142,18 @@ module Puma
|
|
152
142
|
end
|
153
143
|
end
|
154
144
|
|
155
|
-
def parse(binds,
|
145
|
+
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
146
|
+
log_writer ||= @log_writer
|
156
147
|
binds.each do |str|
|
157
148
|
uri = URI.parse str
|
158
149
|
case uri.scheme
|
159
150
|
when "tcp"
|
160
151
|
if fd = @inherited_fds.delete(str)
|
161
152
|
io = inherit_tcp_listener uri.host, uri.port, fd
|
162
|
-
|
153
|
+
log_writer.log "* Inherited #{str}"
|
163
154
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
164
155
|
io = inherit_tcp_listener uri.host, uri.port, sock
|
165
|
-
|
156
|
+
log_writer.log "* Activated #{str}"
|
166
157
|
else
|
167
158
|
ios_len = @ios.length
|
168
159
|
params = Util.parse_query uri.query
|
@@ -174,7 +165,7 @@ module Puma
|
|
174
165
|
|
175
166
|
@ios[ios_len..-1].each do |i|
|
176
167
|
addr = loc_addr_str i
|
177
|
-
|
168
|
+
log_writer.log "* #{log_msg} on http://#{addr}"
|
178
169
|
end
|
179
170
|
end
|
180
171
|
|
@@ -189,14 +180,14 @@ module Puma
|
|
189
180
|
end
|
190
181
|
|
191
182
|
if fd = @inherited_fds.delete(str)
|
192
|
-
@unix_paths << path unless abstract
|
183
|
+
@unix_paths << path unless abstract || File.exist?(path)
|
193
184
|
io = inherit_unix_listener path, fd
|
194
|
-
|
185
|
+
log_writer.log "* Inherited #{str}"
|
195
186
|
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
196
187
|
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
197
188
|
@unix_paths << path unless abstract || File.exist?(path)
|
198
189
|
io = inherit_unix_listener path, sock
|
199
|
-
|
190
|
+
log_writer.log "* Activated #{str}"
|
200
191
|
else
|
201
192
|
umask = nil
|
202
193
|
mode = nil
|
@@ -220,11 +211,12 @@ module Puma
|
|
220
211
|
|
221
212
|
@unix_paths << path unless abstract || File.exist?(path)
|
222
213
|
io = add_unix_listener path, umask, mode, backlog
|
223
|
-
|
214
|
+
log_writer.log "* #{log_msg} on #{str}"
|
224
215
|
end
|
225
216
|
|
226
217
|
@listeners << [str, io]
|
227
218
|
when "ssl"
|
219
|
+
cert_key = %w[cert key]
|
228
220
|
|
229
221
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
230
222
|
|
@@ -233,28 +225,29 @@ module Puma
|
|
233
225
|
# If key and certs are not defined and localhost gem is required.
|
234
226
|
# localhost gem will be used for self signed
|
235
227
|
# Load localhost authority if not loaded.
|
236
|
-
|
228
|
+
# Ruby 3 `values_at` accepts an array, earlier do not
|
229
|
+
if params.values_at(*cert_key).all? { |v| v.to_s.empty? }
|
237
230
|
ctx = localhost_authority && localhost_authority_context
|
238
231
|
end
|
239
232
|
|
240
233
|
ctx ||=
|
241
234
|
begin
|
242
235
|
# Extract cert_pem and key_pem from options[:store] if present
|
243
|
-
|
244
|
-
if params[v]
|
236
|
+
cert_key.each do |v|
|
237
|
+
if params[v]&.start_with?('store:')
|
245
238
|
index = Integer(params.delete(v).split('store:').last)
|
246
239
|
params["#{v}_pem"] = @conf.options[:store][index]
|
247
240
|
end
|
248
241
|
end
|
249
|
-
MiniSSL::ContextBuilder.new(params, @
|
242
|
+
MiniSSL::ContextBuilder.new(params, @log_writer).context
|
250
243
|
end
|
251
244
|
|
252
245
|
if fd = @inherited_fds.delete(str)
|
253
|
-
|
246
|
+
log_writer.log "* Inherited #{str}"
|
254
247
|
io = inherit_ssl_listener fd, ctx
|
255
248
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
256
249
|
io = inherit_ssl_listener sock, ctx
|
257
|
-
|
250
|
+
log_writer.log "* Activated #{str}"
|
258
251
|
else
|
259
252
|
ios_len = @ios.length
|
260
253
|
backlog = params.fetch('backlog', 1024).to_i
|
@@ -262,20 +255,20 @@ module Puma
|
|
262
255
|
|
263
256
|
@ios[ios_len..-1].each do |i|
|
264
257
|
addr = loc_addr_str i
|
265
|
-
|
258
|
+
log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
|
266
259
|
end
|
267
260
|
end
|
268
261
|
|
269
262
|
@listeners << [str, io] if io
|
270
263
|
else
|
271
|
-
|
264
|
+
log_writer.error "Invalid URI: #{str}"
|
272
265
|
end
|
273
266
|
end
|
274
267
|
|
275
268
|
# If we inherited fds but didn't use them (because of a
|
276
269
|
# configuration change), then be sure to close them.
|
277
270
|
@inherited_fds.each do |str, fd|
|
278
|
-
|
271
|
+
log_writer.log "* Closing unused inherited connection: #{str}"
|
279
272
|
|
280
273
|
begin
|
281
274
|
IO.for_fd(fd).close
|
@@ -295,7 +288,7 @@ module Puma
|
|
295
288
|
fds = @ios.map(&:to_i)
|
296
289
|
@activated_sockets.each do |key, sock|
|
297
290
|
next if fds.include? sock.to_i
|
298
|
-
|
291
|
+
log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
|
299
292
|
begin
|
300
293
|
sock.close
|
301
294
|
rescue SystemCallError
|
@@ -319,7 +312,7 @@ module Puma
|
|
319
312
|
local_certificates_path = File.expand_path("~/.localhost")
|
320
313
|
[File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
|
321
314
|
end
|
322
|
-
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @
|
315
|
+
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context
|
323
316
|
end
|
324
317
|
|
325
318
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -482,9 +475,10 @@ module Puma
|
|
482
475
|
|
483
476
|
# @!attribute [r] loopback_addresses
|
484
477
|
def loopback_addresses
|
485
|
-
Socket.ip_address_list.select do |addrinfo|
|
478
|
+
t = Socket.ip_address_list.select do |addrinfo|
|
486
479
|
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
487
|
-
end
|
480
|
+
end
|
481
|
+
t.map! { |addrinfo| addrinfo.ip_address }; t.uniq!; t
|
488
482
|
end
|
489
483
|
|
490
484
|
def loc_addr_str(io)
|
data/lib/puma/cli.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'uri'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require_relative '../puma'
|
7
|
+
require_relative 'configuration'
|
8
|
+
require_relative 'launcher'
|
9
|
+
require_relative 'const'
|
10
|
+
require_relative 'log_writer'
|
11
11
|
|
12
12
|
module Puma
|
13
13
|
class << self
|
@@ -21,19 +21,13 @@ module Puma
|
|
21
21
|
# Handles invoke a Puma::Server in a command line style.
|
22
22
|
#
|
23
23
|
class CLI
|
24
|
-
# @deprecated 6.0.0
|
25
|
-
KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
|
26
|
-
|
27
24
|
# Create a new CLI object using +argv+ as the command line
|
28
25
|
# arguments.
|
29
26
|
#
|
30
|
-
|
31
|
-
# this object will report status on.
|
32
|
-
#
|
33
|
-
def initialize(argv, events=Events.stdio)
|
27
|
+
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new)
|
34
28
|
@debug = false
|
35
29
|
@argv = argv.dup
|
36
|
-
|
30
|
+
@log_writer = log_writer
|
37
31
|
@events = events
|
38
32
|
|
39
33
|
@conf = nil
|
@@ -69,7 +63,7 @@ module Puma
|
|
69
63
|
end
|
70
64
|
end
|
71
65
|
|
72
|
-
@launcher = Puma::Launcher.new(@conf, :events => @events, :argv => argv)
|
66
|
+
@launcher = Puma::Launcher.new(@conf, :log_writer => @log_writer, :events => @events, :argv => argv)
|
73
67
|
end
|
74
68
|
|
75
69
|
attr_reader :launcher
|
@@ -83,7 +77,7 @@ module Puma
|
|
83
77
|
|
84
78
|
private
|
85
79
|
def unsupported(str)
|
86
|
-
@
|
80
|
+
@log_writer.error(str)
|
87
81
|
raise UnsupportedOption
|
88
82
|
end
|
89
83
|
|
@@ -152,7 +146,7 @@ module Puma
|
|
152
146
|
|
153
147
|
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
154
148
|
"Use -b for more advanced options" do |arg|
|
155
|
-
user_config.bind "tcp://#{Configuration::
|
149
|
+
user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
|
156
150
|
end
|
157
151
|
|
158
152
|
o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
|
@@ -186,7 +180,7 @@ module Puma
|
|
186
180
|
end
|
187
181
|
|
188
182
|
o.on "-s", "--silent", "Do not log prompt messages other than errors" do
|
189
|
-
@
|
183
|
+
@log_writer = LogWriter.new(NullIO.new, $stderr)
|
190
184
|
end
|
191
185
|
|
192
186
|
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|
data/lib/puma/client.rb
CHANGED
@@ -8,7 +8,8 @@ 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
14
|
require 'forwardable'
|
14
15
|
|
@@ -25,6 +26,9 @@ module Puma
|
|
25
26
|
|
26
27
|
class HttpParserError501 < IOError; end
|
27
28
|
|
29
|
+
#———————————————————————— DO NOT USE — this class is for internal use only ———
|
30
|
+
|
31
|
+
|
28
32
|
# An instance of this class represents a unique request from a client.
|
29
33
|
# For example, this could be a web request from a browser or from CURL.
|
30
34
|
#
|
@@ -38,7 +42,7 @@ module Puma
|
|
38
42
|
# the header and body are fully buffered via the `try_to_finish` method.
|
39
43
|
# They can be used to "time out" a response via the `timeout_at` reader.
|
40
44
|
#
|
41
|
-
class Client
|
45
|
+
class Client # :nodoc:
|
42
46
|
|
43
47
|
# this tests all values but the last, which must be chunked
|
44
48
|
ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
|
@@ -62,12 +66,9 @@ module Puma
|
|
62
66
|
def initialize(io, env=nil)
|
63
67
|
@io = io
|
64
68
|
@to_io = io.to_io
|
69
|
+
@io_buffer = IOBuffer.new
|
65
70
|
@proto_env = env
|
66
|
-
|
67
|
-
@env = nil
|
68
|
-
else
|
69
|
-
@env = env.dup
|
70
|
-
end
|
71
|
+
@env = env ? env.dup : nil
|
71
72
|
|
72
73
|
@parser = HttpParser.new
|
73
74
|
@parsed_bytes = 0
|
@@ -86,6 +87,7 @@ module Puma
|
|
86
87
|
@hijacked = false
|
87
88
|
|
88
89
|
@peerip = nil
|
90
|
+
@peer_family = nil
|
89
91
|
@listener = nil
|
90
92
|
@remote_addr_header = nil
|
91
93
|
@expect_proxy_proto = false
|
@@ -96,7 +98,7 @@ module Puma
|
|
96
98
|
end
|
97
99
|
|
98
100
|
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
|
99
|
-
:tempfile
|
101
|
+
:tempfile, :io_buffer
|
100
102
|
|
101
103
|
attr_writer :peerip
|
102
104
|
|
@@ -138,6 +140,7 @@ module Puma
|
|
138
140
|
|
139
141
|
def reset(fast_check=true)
|
140
142
|
@parser.reset
|
143
|
+
@io_buffer.reset
|
141
144
|
@read_header = true
|
142
145
|
@read_proxy = !!@expect_proxy_proto
|
143
146
|
@env = @proto_env.dup
|
@@ -273,7 +276,7 @@ module Puma
|
|
273
276
|
return @peerip if @peerip
|
274
277
|
|
275
278
|
if @remote_addr_header
|
276
|
-
hdr = (@env[@remote_addr_header] ||
|
279
|
+
hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
|
277
280
|
@peerip = hdr
|
278
281
|
return hdr
|
279
282
|
end
|
@@ -281,6 +284,16 @@ module Puma
|
|
281
284
|
@peerip ||= @io.peeraddr.last
|
282
285
|
end
|
283
286
|
|
287
|
+
def peer_family
|
288
|
+
return @peer_family if @peer_family
|
289
|
+
|
290
|
+
@peer_family ||= begin
|
291
|
+
@io.local_address.afamily
|
292
|
+
rescue
|
293
|
+
Socket::AF_INET
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
284
297
|
# Returns true if the persistent connection can be closed immediately
|
285
298
|
# without waiting for the configured idle/shutdown timeout.
|
286
299
|
# @version 5.0.0
|
@@ -304,7 +317,7 @@ module Puma
|
|
304
317
|
private
|
305
318
|
|
306
319
|
def setup_body
|
307
|
-
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
320
|
+
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
308
321
|
|
309
322
|
if @env[HTTP_EXPECT] == CONTINUE
|
310
323
|
# TODO allow a hook here to check the headers before
|
@@ -348,7 +361,7 @@ module Puma
|
|
348
361
|
|
349
362
|
if cl
|
350
363
|
# cannot contain characters that are not \d
|
351
|
-
if cl
|
364
|
+
if CONTENT_LENGTH_VALUE_INVALID.match? cl
|
352
365
|
raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
|
353
366
|
end
|
354
367
|
else
|
@@ -513,7 +526,7 @@ module Puma
|
|
513
526
|
# Puma doesn't process chunk extensions, but should parse if they're
|
514
527
|
# present, which is the reason for the semicolon regex
|
515
528
|
chunk_hex = line.strip[/\A[^;]+/]
|
516
|
-
if chunk_hex
|
529
|
+
if CHUNK_SIZE_INVALID.match? chunk_hex
|
517
530
|
raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
|
518
531
|
end
|
519
532
|
len = chunk_hex.to_i(16)
|
@@ -576,7 +589,7 @@ module Puma
|
|
576
589
|
|
577
590
|
def set_ready
|
578
591
|
if @body_read_start
|
579
|
-
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
592
|
+
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
|
580
593
|
end
|
581
594
|
@requests_served += 1
|
582
595
|
@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
|
@@ -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,8 +86,7 @@ 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
|
89
91
|
elsif idx == 0 # restart server
|
90
92
|
restart_server << true << false
|
@@ -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,7 +167,7 @@ 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
173
|
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
|