puma 5.0.2-java → 5.2.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 +667 -567
- data/README.md +51 -21
- data/bin/puma-wild +3 -9
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +6 -7
- data/docs/fork_worker.md +2 -0
- data/docs/jungle/README.md +0 -4
- data/docs/jungle/rc.d/puma +2 -2
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +1 -1
- data/docs/restart.md +46 -23
- data/docs/stats.md +142 -0
- data/docs/systemd.md +25 -3
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +18 -5
- data/ext/puma_http11/http11_parser.c +45 -47
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +199 -119
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +5 -7
- data/ext/puma_http11/puma_http11.c +25 -12
- data/lib/puma.rb +2 -2
- data/lib/puma/app/status.rb +44 -46
- data/lib/puma/binder.rb +69 -25
- data/lib/puma/cli.rb +4 -0
- data/lib/puma/client.rb +26 -79
- data/lib/puma/cluster.rb +37 -202
- data/lib/puma/cluster/worker.rb +176 -0
- data/lib/puma/cluster/worker_handle.rb +86 -0
- data/lib/puma/configuration.rb +21 -8
- data/lib/puma/const.rb +11 -3
- data/lib/puma/control_cli.rb +73 -70
- data/lib/puma/dsl.rb +100 -22
- data/lib/puma/error_logger.rb +10 -3
- data/lib/puma/events.rb +18 -3
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +57 -15
- data/lib/puma/minissl.rb +47 -16
- data/lib/puma/minissl/context_builder.rb +6 -0
- data/lib/puma/null_io.rb +4 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/reactor.rb +85 -363
- data/lib/puma/request.rb +451 -0
- data/lib/puma/runner.rb +17 -23
- data/lib/puma/server.rb +164 -553
- data/lib/puma/single.rb +2 -2
- data/lib/puma/state_file.rb +5 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/util.rb +11 -0
- metadata +11 -6
- data/docs/jungle/upstart/README.md +0 -61
- data/docs/jungle/upstart/puma-manager.conf +0 -31
- data/docs/jungle/upstart/puma.conf +0 -69
- data/lib/puma/accept_nonblock.rb +0 -29
data/lib/puma/cli.rb
CHANGED
|
@@ -104,6 +104,10 @@ module Puma
|
|
|
104
104
|
user_config.bind arg
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
+
o.on "--bind-to-activated-sockets [only]", "Bind to all activated sockets" do |arg|
|
|
108
|
+
user_config.bind_to_activated_sockets(arg || true)
|
|
109
|
+
end
|
|
110
|
+
|
|
107
111
|
o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
|
|
108
112
|
file_config.load arg
|
|
109
113
|
end
|
data/lib/puma/client.rb
CHANGED
|
@@ -85,6 +85,12 @@ module Puma
|
|
|
85
85
|
|
|
86
86
|
def_delegators :@io, :closed?
|
|
87
87
|
|
|
88
|
+
# Test to see if io meets a bare minimum of functioning, @to_io needs to be
|
|
89
|
+
# used for MiniSSL::Socket
|
|
90
|
+
def io_ok?
|
|
91
|
+
@to_io.is_a?(::BasicSocket) && !closed?
|
|
92
|
+
end
|
|
93
|
+
|
|
88
94
|
# @!attribute [r] inspect
|
|
89
95
|
def inspect
|
|
90
96
|
"#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
|
|
@@ -103,7 +109,12 @@ module Puma
|
|
|
103
109
|
end
|
|
104
110
|
|
|
105
111
|
def set_timeout(val)
|
|
106
|
-
@timeout_at =
|
|
112
|
+
@timeout_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + val
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Number of seconds until the timeout elapses.
|
|
116
|
+
def timeout
|
|
117
|
+
[@timeout_at - Process.clock_gettime(Process::CLOCK_MONOTONIC), 0].max
|
|
107
118
|
end
|
|
108
119
|
|
|
109
120
|
def reset(fast_check=true)
|
|
@@ -188,79 +199,20 @@ module Puma
|
|
|
188
199
|
false
|
|
189
200
|
end
|
|
190
201
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
data = @io.sysread_nonblock(CHUNK_SIZE)
|
|
197
|
-
rescue OpenSSL::SSL::SSLError => e
|
|
198
|
-
return false if e.kind_of? IO::WaitReadable
|
|
199
|
-
raise e
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# No data means a closed socket
|
|
203
|
-
unless data
|
|
204
|
-
@buffer = nil
|
|
205
|
-
set_ready
|
|
206
|
-
raise EOFError
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
if @buffer
|
|
210
|
-
@buffer << data
|
|
211
|
-
else
|
|
212
|
-
@buffer = data
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
|
216
|
-
|
|
217
|
-
if @parser.finished?
|
|
218
|
-
return setup_body
|
|
219
|
-
elsif @parsed_bytes >= MAX_HEADER
|
|
220
|
-
raise HttpParserError,
|
|
221
|
-
"HEADER is longer than allowed, aborting client early."
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
false
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def eagerly_finish
|
|
228
|
-
return true if @ready
|
|
229
|
-
|
|
230
|
-
if @io.kind_of? OpenSSL::SSL::SSLSocket
|
|
231
|
-
return true if jruby_start_try_to_finish
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
return false unless IO.select([@to_io], nil, nil, 0)
|
|
235
|
-
try_to_finish
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
else
|
|
239
|
-
|
|
240
|
-
def eagerly_finish
|
|
241
|
-
return true if @ready
|
|
242
|
-
return false unless IO.select([@to_io], nil, nil, 0)
|
|
243
|
-
try_to_finish
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
# For documentation, see https://github.com/puma/puma/issues/1754
|
|
247
|
-
send(:alias_method, :jruby_eagerly_finish, :eagerly_finish)
|
|
248
|
-
end # IS_JRUBY
|
|
202
|
+
def eagerly_finish
|
|
203
|
+
return true if @ready
|
|
204
|
+
return false unless IO.select([@to_io], nil, nil, 0)
|
|
205
|
+
try_to_finish
|
|
206
|
+
end
|
|
249
207
|
|
|
250
208
|
def finish(timeout)
|
|
251
|
-
return
|
|
252
|
-
until try_to_finish
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
unless can_read
|
|
259
|
-
write_error(408) if in_data_phase
|
|
260
|
-
raise ConnectionError
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
true
|
|
209
|
+
return if @ready
|
|
210
|
+
IO.select([@to_io], nil, nil, timeout) || timeout! until try_to_finish
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def timeout!
|
|
214
|
+
write_error(408) if in_data_phase
|
|
215
|
+
raise ConnectionError
|
|
264
216
|
end
|
|
265
217
|
|
|
266
218
|
def write_error(status_code)
|
|
@@ -287,13 +239,8 @@ module Puma
|
|
|
287
239
|
# @version 5.0.0
|
|
288
240
|
#
|
|
289
241
|
def can_close?
|
|
290
|
-
# Allow connection to close if
|
|
291
|
-
|
|
292
|
-
#
|
|
293
|
-
# From RFC 2616 section 8.1.4:
|
|
294
|
-
# Servers SHOULD always respond to at least one request per connection,
|
|
295
|
-
# if at all possible.
|
|
296
|
-
@requests_served > 0 && @parsed_bytes == 0
|
|
242
|
+
# Allow connection to close if we're not in the middle of parsing a request.
|
|
243
|
+
@parsed_bytes == 0
|
|
297
244
|
end
|
|
298
245
|
|
|
299
246
|
private
|
data/lib/puma/cluster.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require 'puma/runner'
|
|
4
4
|
require 'puma/util'
|
|
5
5
|
require 'puma/plugin'
|
|
6
|
+
require 'puma/cluster/worker_handle'
|
|
7
|
+
require 'puma/cluster/worker'
|
|
6
8
|
|
|
7
9
|
require 'time'
|
|
8
10
|
|
|
@@ -11,10 +13,6 @@ module Puma
|
|
|
11
13
|
# to boot and serve a Ruby application when puma "workers" are needed
|
|
12
14
|
# i.e. when using multi-processes. For example `$ puma -w 5`
|
|
13
15
|
#
|
|
14
|
-
# At the core of this class is running an instance of `Puma::Server` which
|
|
15
|
-
# gets created via the `start_server` method from the `Puma::Runner` class
|
|
16
|
-
# that this inherits from.
|
|
17
|
-
#
|
|
18
16
|
# An instance of this class will spawn the number of processes passed in
|
|
19
17
|
# via the `spawn_workers` method call. Each worker will have it's own
|
|
20
18
|
# instance of a `Puma::Server`.
|
|
@@ -61,79 +59,6 @@ module Puma
|
|
|
61
59
|
@workers.each { |x| x.hup }
|
|
62
60
|
end
|
|
63
61
|
|
|
64
|
-
class Worker
|
|
65
|
-
def initialize(idx, pid, phase, options)
|
|
66
|
-
@index = idx
|
|
67
|
-
@pid = pid
|
|
68
|
-
@phase = phase
|
|
69
|
-
@stage = :started
|
|
70
|
-
@signal = "TERM"
|
|
71
|
-
@options = options
|
|
72
|
-
@first_term_sent = nil
|
|
73
|
-
@started_at = Time.now
|
|
74
|
-
@last_checkin = Time.now
|
|
75
|
-
@last_status = {}
|
|
76
|
-
@term = false
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
|
|
80
|
-
|
|
81
|
-
# @version 5.0.0
|
|
82
|
-
attr_writer :pid, :phase
|
|
83
|
-
|
|
84
|
-
def booted?
|
|
85
|
-
@stage == :booted
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def boot!
|
|
89
|
-
@last_checkin = Time.now
|
|
90
|
-
@stage = :booted
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def term?
|
|
94
|
-
@term
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def ping!(status)
|
|
98
|
-
@last_checkin = Time.now
|
|
99
|
-
require 'json'
|
|
100
|
-
@last_status = JSON.parse(status, symbolize_names: true)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# @see Puma::Cluster#check_workers
|
|
104
|
-
# @version 5.0.0
|
|
105
|
-
def ping_timeout
|
|
106
|
-
@last_checkin +
|
|
107
|
-
(booted? ?
|
|
108
|
-
@options[:worker_timeout] :
|
|
109
|
-
@options[:worker_boot_timeout]
|
|
110
|
-
)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def term
|
|
114
|
-
begin
|
|
115
|
-
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
|
116
|
-
@signal = "KILL"
|
|
117
|
-
else
|
|
118
|
-
@term ||= true
|
|
119
|
-
@first_term_sent ||= Time.now
|
|
120
|
-
end
|
|
121
|
-
Process.kill @signal, @pid if @pid
|
|
122
|
-
rescue Errno::ESRCH
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def kill
|
|
127
|
-
@signal = 'KILL'
|
|
128
|
-
term
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def hup
|
|
132
|
-
Process.kill "HUP", @pid
|
|
133
|
-
rescue Errno::ESRCH
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
62
|
def spawn_workers
|
|
138
63
|
diff = @options[:workers] - @workers.size
|
|
139
64
|
return if diff < 1
|
|
@@ -154,7 +79,7 @@ module Puma
|
|
|
154
79
|
end
|
|
155
80
|
|
|
156
81
|
debug "Spawned worker: #{pid}"
|
|
157
|
-
@workers <<
|
|
82
|
+
@workers << WorkerHandle.new(idx, pid, @phase, @options)
|
|
158
83
|
end
|
|
159
84
|
|
|
160
85
|
if @options[:fork_worker] &&
|
|
@@ -189,7 +114,7 @@ module Puma
|
|
|
189
114
|
debug "Workers to cull: #{workers_to_cull.inspect}"
|
|
190
115
|
|
|
191
116
|
workers_to_cull.each do |worker|
|
|
192
|
-
log "- Worker #{worker.index} (
|
|
117
|
+
log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
|
|
193
118
|
worker.term
|
|
194
119
|
end
|
|
195
120
|
end
|
|
@@ -249,113 +174,25 @@ module Puma
|
|
|
249
174
|
end
|
|
250
175
|
|
|
251
176
|
def worker(index, master)
|
|
252
|
-
title = "puma: cluster worker #{index}: #{master}"
|
|
253
|
-
title += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
|
254
|
-
$0 = title
|
|
255
|
-
|
|
256
|
-
Signal.trap "SIGINT", "IGNORE"
|
|
257
|
-
Signal.trap "SIGCHLD", "DEFAULT"
|
|
258
|
-
|
|
259
|
-
fork_worker = @options[:fork_worker] && index == 0
|
|
260
|
-
|
|
261
177
|
@workers = []
|
|
262
|
-
if !@options[:fork_worker] || fork_worker
|
|
263
|
-
@master_read.close
|
|
264
|
-
@suicide_pipe.close
|
|
265
|
-
@fork_writer.close
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
Thread.new do
|
|
269
|
-
Puma.set_thread_name "worker check pipe"
|
|
270
|
-
IO.select [@check_pipe]
|
|
271
|
-
log "! Detected parent died, dying"
|
|
272
|
-
exit! 1
|
|
273
|
-
end
|
|
274
178
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if File.exist?("Gemfile")
|
|
279
|
-
log "+ Gemfile in context: #{File.expand_path("Gemfile")}"
|
|
280
|
-
elsif File.exist?("gems.rb")
|
|
281
|
-
log "+ Gemfile in context: #{File.expand_path("gems.rb")}"
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
# Invoke any worker boot hooks so they can get
|
|
286
|
-
# things in shape before booting the app.
|
|
287
|
-
@launcher.config.run_hooks :before_worker_boot, index, @launcher.events
|
|
288
|
-
|
|
289
|
-
server = @server ||= start_server
|
|
290
|
-
restart_server = Queue.new << true << false
|
|
291
|
-
|
|
292
|
-
if fork_worker
|
|
293
|
-
restart_server.clear
|
|
294
|
-
worker_pids = []
|
|
295
|
-
Signal.trap "SIGCHLD" do
|
|
296
|
-
wakeup! if worker_pids.reject! do |p|
|
|
297
|
-
Process.wait(p, Process::WNOHANG) rescue true
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
Thread.new do
|
|
302
|
-
Puma.set_thread_name "worker fork pipe"
|
|
303
|
-
while (idx = @fork_pipe.gets)
|
|
304
|
-
idx = idx.to_i
|
|
305
|
-
if idx == -1 # stop server
|
|
306
|
-
if restart_server.length > 0
|
|
307
|
-
restart_server.clear
|
|
308
|
-
server.begin_restart(true)
|
|
309
|
-
@launcher.config.run_hooks :before_refork, nil, @launcher.events
|
|
310
|
-
nakayoshi_gc
|
|
311
|
-
end
|
|
312
|
-
elsif idx == 0 # restart server
|
|
313
|
-
restart_server << true << false
|
|
314
|
-
else # fork worker
|
|
315
|
-
worker_pids << pid = spawn_worker(idx, master)
|
|
316
|
-
@worker_write << "f#{pid}:#{idx}\n" rescue nil
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
Signal.trap "SIGTERM" do
|
|
323
|
-
@worker_write << "e#{Process.pid}\n" rescue nil
|
|
324
|
-
server.stop
|
|
325
|
-
restart_server << false
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
begin
|
|
329
|
-
@worker_write << "b#{Process.pid}:#{index}\n"
|
|
330
|
-
rescue SystemCallError, IOError
|
|
331
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
332
|
-
STDERR.puts "Master seems to have exited, exiting."
|
|
333
|
-
return
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
Thread.new(@worker_write) do |io|
|
|
337
|
-
Puma.set_thread_name "stat payload"
|
|
179
|
+
@master_read.close
|
|
180
|
+
@suicide_pipe.close
|
|
181
|
+
@fork_writer.close
|
|
338
182
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
io << "p#{Process.pid}#{server.stats.to_json}\n"
|
|
344
|
-
rescue IOError
|
|
345
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
346
|
-
break
|
|
347
|
-
end
|
|
348
|
-
end
|
|
183
|
+
pipes = { check_pipe: @check_pipe, worker_write: @worker_write }
|
|
184
|
+
if @options[:fork_worker]
|
|
185
|
+
pipes[:fork_pipe] = @fork_pipe
|
|
186
|
+
pipes[:wakeup] = @wakeup
|
|
349
187
|
end
|
|
350
188
|
|
|
351
|
-
server
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
@worker_write.close
|
|
189
|
+
server = start_server if preload?
|
|
190
|
+
new_worker = Worker.new index: index,
|
|
191
|
+
master: master,
|
|
192
|
+
launcher: @launcher,
|
|
193
|
+
pipes: pipes,
|
|
194
|
+
server: server
|
|
195
|
+
new_worker.run
|
|
359
196
|
end
|
|
360
197
|
|
|
361
198
|
def restart
|
|
@@ -492,15 +329,19 @@ module Puma
|
|
|
492
329
|
|
|
493
330
|
output_header "cluster"
|
|
494
331
|
|
|
495
|
-
|
|
332
|
+
# This is aligned with the output from Runner, see Runner#output_header
|
|
333
|
+
log "* Workers: #{@options[:workers]}"
|
|
496
334
|
|
|
497
|
-
|
|
335
|
+
# Threads explicitly marked as fork safe will be ignored.
|
|
336
|
+
# Used in Rails, but may be used by anyone.
|
|
337
|
+
before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
|
498
338
|
|
|
499
339
|
if preload?
|
|
340
|
+
log "* Restarts: (\u2714) hot (\u2716) phased"
|
|
500
341
|
log "* Preloading application"
|
|
501
342
|
load_and_bind
|
|
502
343
|
|
|
503
|
-
after = Thread.list
|
|
344
|
+
after = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
|
504
345
|
|
|
505
346
|
if after.size > before.size
|
|
506
347
|
threads = (after - before)
|
|
@@ -514,7 +355,7 @@ module Puma
|
|
|
514
355
|
end
|
|
515
356
|
end
|
|
516
357
|
else
|
|
517
|
-
log "*
|
|
358
|
+
log "* Restarts: (\u2714) hot (\u2714) phased"
|
|
518
359
|
|
|
519
360
|
unless @launcher.config.app_configured?
|
|
520
361
|
error "No application configured, nothing to run"
|
|
@@ -552,7 +393,7 @@ module Puma
|
|
|
552
393
|
@master_read, @worker_write = read, @wakeup
|
|
553
394
|
|
|
554
395
|
@launcher.config.run_hooks :before_fork, nil, @launcher.events
|
|
555
|
-
nakayoshi_gc
|
|
396
|
+
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
|
556
397
|
|
|
557
398
|
spawn_workers
|
|
558
399
|
|
|
@@ -560,9 +401,9 @@ module Puma
|
|
|
560
401
|
stop
|
|
561
402
|
end
|
|
562
403
|
|
|
563
|
-
@launcher.events.fire_on_booted!
|
|
564
|
-
|
|
565
404
|
begin
|
|
405
|
+
booted = false
|
|
406
|
+
|
|
566
407
|
while @status == :run
|
|
567
408
|
begin
|
|
568
409
|
if @phased_restart
|
|
@@ -593,7 +434,7 @@ module Puma
|
|
|
593
434
|
case req
|
|
594
435
|
when "b"
|
|
595
436
|
w.boot!
|
|
596
|
-
log "- Worker #{w.index} (
|
|
437
|
+
log "- Worker #{w.index} (PID: #{pid}) booted, phase: #{w.phase}"
|
|
597
438
|
@next_check = Time.now
|
|
598
439
|
when "e"
|
|
599
440
|
# external term, see worker method, Signal.trap "SIGTERM"
|
|
@@ -603,6 +444,10 @@ module Puma
|
|
|
603
444
|
when "p"
|
|
604
445
|
w.ping!(result.sub(/^\d+/,'').chomp)
|
|
605
446
|
@launcher.events.fire(:ping!, w)
|
|
447
|
+
if !booted && @workers.none? {|worker| worker.last_status.empty?}
|
|
448
|
+
@launcher.events.fire_on_booted!
|
|
449
|
+
booted = true
|
|
450
|
+
end
|
|
606
451
|
end
|
|
607
452
|
else
|
|
608
453
|
log "! Out-of-sync worker list, no #{pid} worker"
|
|
@@ -640,7 +485,9 @@ module Puma
|
|
|
640
485
|
rescue Errno::ECHILD
|
|
641
486
|
begin
|
|
642
487
|
Process.kill(0, w.pid)
|
|
643
|
-
|
|
488
|
+
# child still alive but has another parent (e.g., using fork_worker)
|
|
489
|
+
w.term if w.term?
|
|
490
|
+
false
|
|
644
491
|
rescue Errno::ESRCH, Errno::EPERM
|
|
645
492
|
true # child is already terminated
|
|
646
493
|
end
|
|
@@ -657,17 +504,5 @@ module Puma
|
|
|
657
504
|
end
|
|
658
505
|
end
|
|
659
506
|
end
|
|
660
|
-
|
|
661
|
-
# @version 5.0.0
|
|
662
|
-
def nakayoshi_gc
|
|
663
|
-
return unless @options[:nakayoshi_fork]
|
|
664
|
-
log "! Promoting existing objects to old generation..."
|
|
665
|
-
4.times { GC.start(full_mark: false) }
|
|
666
|
-
if GC.respond_to?(:compact)
|
|
667
|
-
log "! Compacting..."
|
|
668
|
-
GC.compact
|
|
669
|
-
end
|
|
670
|
-
log "! Friendly fork preparation complete."
|
|
671
|
-
end
|
|
672
507
|
end
|
|
673
508
|
end
|