puma 2.7.0 → 3.1.1
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 +5 -13
- data/DEPLOYMENT.md +91 -0
- data/Gemfile +3 -2
- data/History.txt +624 -1
- data/Manifest.txt +15 -3
- data/README.md +129 -14
- data/Rakefile +3 -3
- data/bin/puma-wild +31 -0
- data/bin/pumactl +1 -1
- data/docs/nginx.md +1 -1
- data/docs/signals.md +43 -0
- data/ext/puma_http11/extconf.rb +7 -2
- data/ext/puma_http11/http11_parser.java.rl +5 -5
- data/ext/puma_http11/io_buffer.c +1 -1
- data/ext/puma_http11/mini_ssl.c +233 -18
- data/ext/puma_http11/org/jruby/puma/Http11.java +12 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +245 -195
- data/ext/puma_http11/puma_http11.c +12 -4
- data/lib/puma.rb +1 -0
- data/lib/puma/app/status.rb +7 -0
- data/lib/puma/binder.rb +108 -39
- data/lib/puma/capistrano.rb +23 -6
- data/lib/puma/cli.rb +141 -446
- data/lib/puma/client.rb +48 -1
- data/lib/puma/cluster.rb +207 -58
- data/lib/puma/commonlogger.rb +107 -0
- data/lib/puma/configuration.rb +262 -235
- data/lib/puma/const.rb +97 -14
- data/lib/puma/control_cli.rb +85 -77
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +11 -4
- data/lib/puma/detect.rb +8 -1
- data/lib/puma/dsl.rb +456 -0
- data/lib/puma/events.rb +35 -18
- data/lib/puma/jruby_restart.rb +1 -1
- data/lib/puma/launcher.rb +399 -0
- data/lib/puma/minissl.rb +49 -20
- data/lib/puma/null_io.rb +15 -0
- data/lib/puma/plugin.rb +104 -0
- data/lib/puma/plugin/tmp_restart.rb +35 -0
- data/lib/puma/rack/backports/uri/common_18.rb +56 -0
- data/lib/puma/rack/backports/uri/common_192.rb +52 -0
- data/lib/puma/rack/backports/uri/common_193.rb +29 -0
- data/lib/puma/rack/builder.rb +295 -0
- data/lib/puma/rack/urlmap.rb +90 -0
- data/lib/puma/reactor.rb +14 -1
- data/lib/puma/runner.rb +35 -17
- data/lib/puma/server.rb +161 -58
- data/lib/puma/single.rb +15 -10
- data/lib/puma/state_file.rb +29 -0
- data/lib/puma/thread_pool.rb +88 -13
- data/lib/puma/util.rb +123 -0
- data/lib/rack/handler/puma.rb +35 -29
- data/puma.gemspec +2 -4
- data/tools/jungle/init.d/README.md +2 -2
- data/tools/jungle/init.d/puma +69 -7
- data/tools/jungle/upstart/puma.conf +8 -2
- metadata +51 -71
- data/COPYING +0 -55
- data/TODO +0 -5
- data/lib/puma/rack_patch.rb +0 -45
- data/test/test_app_status.rb +0 -92
- data/test/test_cli.rb +0 -173
- data/test/test_config.rb +0 -16
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -145
- data/test/test_integration.rb +0 -165
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -25
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -292
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -141
- data/test/test_tcp_rack.rb +0 -42
- data/test/test_thread_pool.rb +0 -156
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
data/lib/puma/client.rb
CHANGED
@@ -7,6 +7,7 @@ class IO
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require 'puma/detect'
|
10
|
+
require 'puma/delegation'
|
10
11
|
|
11
12
|
if Puma::IS_JRUBY
|
12
13
|
# We have to work around some OpenSSL buffer/io-readiness bugs
|
@@ -21,6 +22,7 @@ module Puma
|
|
21
22
|
|
22
23
|
class Client
|
23
24
|
include Puma::Const
|
25
|
+
extend Puma::Delegation
|
24
26
|
|
25
27
|
def initialize(io, env=nil)
|
26
28
|
@io = io
|
@@ -39,14 +41,25 @@ module Puma
|
|
39
41
|
|
40
42
|
@body = nil
|
41
43
|
@buffer = nil
|
44
|
+
@tempfile = nil
|
42
45
|
|
43
46
|
@timeout_at = nil
|
44
47
|
|
45
48
|
@requests_served = 0
|
46
49
|
@hijacked = false
|
50
|
+
|
51
|
+
@peerip = nil
|
52
|
+
@remote_addr_header = nil
|
47
53
|
end
|
48
54
|
|
49
|
-
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked
|
55
|
+
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
|
56
|
+
:tempfile
|
57
|
+
|
58
|
+
attr_writer :peerip
|
59
|
+
|
60
|
+
attr_accessor :remote_addr_header
|
61
|
+
|
62
|
+
forward :closed?, :@io
|
50
63
|
|
51
64
|
def inspect
|
52
65
|
"#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
|
@@ -59,6 +72,10 @@ module Puma
|
|
59
72
|
env[HIJACK_IO] ||= @io
|
60
73
|
end
|
61
74
|
|
75
|
+
def in_data_phase
|
76
|
+
!@read_header
|
77
|
+
end
|
78
|
+
|
62
79
|
def set_timeout(val)
|
63
80
|
@timeout_at = Time.now + val
|
64
81
|
end
|
@@ -68,6 +85,7 @@ module Puma
|
|
68
85
|
@read_header = true
|
69
86
|
@env = @proto_env.dup
|
70
87
|
@body = nil
|
88
|
+
@tempfile = nil
|
71
89
|
@parsed_bytes = 0
|
72
90
|
@ready = false
|
73
91
|
|
@@ -100,6 +118,7 @@ module Puma
|
|
100
118
|
EmptyBody = NullIO.new
|
101
119
|
|
102
120
|
def setup_body
|
121
|
+
@in_data_phase = true
|
103
122
|
body = @parser.body
|
104
123
|
cl = @env[CONTENT_LENGTH]
|
105
124
|
|
@@ -124,6 +143,7 @@ module Puma
|
|
124
143
|
if remain > MAX_BODY
|
125
144
|
@body = Tempfile.new(Const::PUMA_TMP_BASE)
|
126
145
|
@body.binmode
|
146
|
+
@tempfile = @body
|
127
147
|
else
|
128
148
|
# The body[0,0] trick is to get an empty string in the same
|
129
149
|
# encoding as body.
|
@@ -217,6 +237,14 @@ module Puma
|
|
217
237
|
end
|
218
238
|
end # IS_JRUBY
|
219
239
|
|
240
|
+
def finish
|
241
|
+
return true if @ready
|
242
|
+
until try_to_finish
|
243
|
+
IO.select([@to_io], nil, nil)
|
244
|
+
end
|
245
|
+
true
|
246
|
+
end
|
247
|
+
|
220
248
|
def read_body
|
221
249
|
# Read an odd sized chunk so we can read even sized ones
|
222
250
|
# after this
|
@@ -267,11 +295,30 @@ module Puma
|
|
267
295
|
end
|
268
296
|
end
|
269
297
|
|
298
|
+
def write_408
|
299
|
+
begin
|
300
|
+
@io << ERROR_408_RESPONSE
|
301
|
+
rescue StandardError
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
270
305
|
def write_500
|
271
306
|
begin
|
272
307
|
@io << ERROR_500_RESPONSE
|
273
308
|
rescue StandardError
|
274
309
|
end
|
275
310
|
end
|
311
|
+
|
312
|
+
def peerip
|
313
|
+
return @peerip if @peerip
|
314
|
+
|
315
|
+
if @remote_addr_header
|
316
|
+
hdr = (@env[@remote_addr_header] || LOCALHOST_ADDR).split(/[\s,]/).first
|
317
|
+
@peerip = hdr
|
318
|
+
return hdr
|
319
|
+
end
|
320
|
+
|
321
|
+
@peerip ||= @io.peeraddr.last
|
322
|
+
end
|
276
323
|
end
|
277
324
|
end
|
data/lib/puma/cluster.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'puma/runner'
|
2
|
+
require 'time'
|
2
3
|
|
3
4
|
module Puma
|
4
5
|
class Cluster < Runner
|
5
|
-
def initialize(cli)
|
6
|
-
super cli
|
6
|
+
def initialize(cli, events)
|
7
|
+
super cli, events
|
7
8
|
|
8
9
|
@phase = 0
|
9
10
|
@workers = []
|
11
|
+
@next_check = nil
|
10
12
|
|
11
13
|
@phased_state = :idle
|
12
14
|
@phased_restart = false
|
@@ -26,51 +28,101 @@ module Puma
|
|
26
28
|
def start_phased_restart
|
27
29
|
@phase += 1
|
28
30
|
log "- Starting phased worker restart, phase: #{@phase}"
|
31
|
+
|
32
|
+
# Be sure to change the directory again before loading
|
33
|
+
# the app. This way we can pick up new code.
|
34
|
+
if dir = @options[:worker_directory]
|
35
|
+
log "+ Changing to #{dir}"
|
36
|
+
Dir.chdir dir
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def redirect_io
|
41
|
+
super
|
42
|
+
|
43
|
+
@workers.each { |x| x.hup }
|
29
44
|
end
|
30
45
|
|
31
46
|
class Worker
|
32
|
-
def initialize(pid, phase)
|
47
|
+
def initialize(idx, pid, phase, options)
|
48
|
+
@index = idx
|
33
49
|
@pid = pid
|
34
50
|
@phase = phase
|
35
51
|
@stage = :started
|
36
52
|
@signal = "TERM"
|
53
|
+
@options = options
|
54
|
+
@first_term_sent = nil
|
55
|
+
@last_checkin = Time.now
|
56
|
+
@last_status = '{}'
|
57
|
+
@dead = false
|
37
58
|
end
|
38
59
|
|
39
|
-
attr_reader :pid, :phase, :signal
|
60
|
+
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status
|
40
61
|
|
41
62
|
def booted?
|
42
63
|
@stage == :booted
|
43
64
|
end
|
44
65
|
|
45
66
|
def boot!
|
67
|
+
@last_checkin = Time.now
|
46
68
|
@stage = :booted
|
47
69
|
end
|
48
70
|
|
71
|
+
def dead?
|
72
|
+
@dead
|
73
|
+
end
|
74
|
+
|
75
|
+
def dead!
|
76
|
+
@dead = true
|
77
|
+
end
|
78
|
+
|
79
|
+
def ping!(status)
|
80
|
+
@last_checkin = Time.now
|
81
|
+
@last_status = status
|
82
|
+
end
|
83
|
+
|
84
|
+
def ping_timeout?(which)
|
85
|
+
Time.now - @last_checkin > which
|
86
|
+
end
|
87
|
+
|
49
88
|
def term
|
50
89
|
begin
|
51
|
-
if @first_term_sent && (Time.
|
90
|
+
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
52
91
|
@signal = "KILL"
|
53
92
|
else
|
54
|
-
@first_term_sent ||= Time.
|
93
|
+
@first_term_sent ||= Time.now
|
55
94
|
end
|
56
95
|
|
57
96
|
Process.kill @signal, @pid
|
58
97
|
rescue Errno::ESRCH
|
59
98
|
end
|
60
99
|
end
|
100
|
+
|
101
|
+
def kill
|
102
|
+
Process.kill "KILL", @pid
|
103
|
+
rescue Errno::ESRCH
|
104
|
+
end
|
105
|
+
|
106
|
+
def hup
|
107
|
+
Process.kill "HUP", @pid
|
108
|
+
rescue Errno::ESRCH
|
109
|
+
end
|
61
110
|
end
|
62
111
|
|
63
112
|
def spawn_workers
|
64
113
|
diff = @options[:workers] - @workers.size
|
65
114
|
|
66
|
-
upgrade = (@phased_state == :waiting)
|
67
|
-
|
68
115
|
master = Process.pid
|
69
116
|
|
70
117
|
diff.times do
|
71
|
-
|
72
|
-
@
|
73
|
-
|
118
|
+
idx = next_worker_index
|
119
|
+
@launcher.config.run_hooks :before_worker_fork, idx
|
120
|
+
|
121
|
+
pid = fork { worker(idx, master) }
|
122
|
+
debug "Spawned worker: #{pid}"
|
123
|
+
@workers << Worker.new(idx, pid, @phase, @options)
|
124
|
+
|
125
|
+
@launcher.config.run_hooks :after_worker_fork, idx
|
74
126
|
end
|
75
127
|
|
76
128
|
if diff > 0
|
@@ -78,11 +130,37 @@ module Puma
|
|
78
130
|
end
|
79
131
|
end
|
80
132
|
|
133
|
+
def next_worker_index
|
134
|
+
all_positions = 0...@options[:workers]
|
135
|
+
occupied_positions = @workers.map { |w| w.index }
|
136
|
+
available_positions = all_positions.to_a - occupied_positions
|
137
|
+
available_positions.first
|
138
|
+
end
|
139
|
+
|
81
140
|
def all_workers_booted?
|
82
141
|
@workers.count { |w| !w.booted? } == 0
|
83
142
|
end
|
84
143
|
|
85
|
-
def check_workers
|
144
|
+
def check_workers(force=false)
|
145
|
+
return if !force && @next_check && @next_check >= Time.now
|
146
|
+
|
147
|
+
@next_check = Time.now + 5
|
148
|
+
|
149
|
+
any = false
|
150
|
+
|
151
|
+
@workers.each do |w|
|
152
|
+
next if !w.booted? && !w.ping_timeout?(@options[:worker_boot_timeout])
|
153
|
+
if w.ping_timeout?(@options[:worker_timeout])
|
154
|
+
log "! Terminating timed out worker: #{w.pid}"
|
155
|
+
w.kill
|
156
|
+
any = true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# If we killed any timed out workers, try to catch them
|
161
|
+
# during this loop by giving the kernel time to kill them.
|
162
|
+
sleep 1 if any
|
163
|
+
|
86
164
|
while @workers.any?
|
87
165
|
pid = Process.waitpid(-1, Process::WNOHANG)
|
88
166
|
break unless pid
|
@@ -90,6 +168,8 @@ module Puma
|
|
90
168
|
@workers.delete_if { |w| w.pid == pid }
|
91
169
|
end
|
92
170
|
|
171
|
+
@workers.delete_if(&:dead?)
|
172
|
+
|
93
173
|
spawn_workers
|
94
174
|
|
95
175
|
if all_workers_booted?
|
@@ -112,16 +192,22 @@ module Puma
|
|
112
192
|
end
|
113
193
|
|
114
194
|
def wakeup!
|
195
|
+
return unless @wakeup
|
196
|
+
|
115
197
|
begin
|
116
198
|
@wakeup.write "!" unless @wakeup.closed?
|
117
199
|
rescue SystemCallError, IOError
|
118
200
|
end
|
119
201
|
end
|
120
202
|
|
121
|
-
def worker(
|
122
|
-
|
203
|
+
def worker(index, master)
|
204
|
+
title = "puma: cluster worker #{index}: #{master}"
|
205
|
+
title << " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
206
|
+
$0 = title
|
207
|
+
|
123
208
|
Signal.trap "SIGINT", "IGNORE"
|
124
209
|
|
210
|
+
@workers = []
|
125
211
|
@master_read.close
|
126
212
|
@suicide_pipe.close
|
127
213
|
|
@@ -131,19 +217,15 @@ module Puma
|
|
131
217
|
exit! 1
|
132
218
|
end
|
133
219
|
|
134
|
-
#
|
135
|
-
# the
|
136
|
-
if
|
137
|
-
|
138
|
-
log "+ Changing to #{dir}"
|
139
|
-
Dir.chdir dir
|
140
|
-
end
|
220
|
+
# If we're not running under a Bundler context, then
|
221
|
+
# report the info about the context we will be using
|
222
|
+
if !ENV['BUNDLE_GEMFILE'] and File.exist?("Gemfile")
|
223
|
+
log "+ Gemfile in context: #{File.expand_path("Gemfile")}"
|
141
224
|
end
|
142
225
|
|
143
226
|
# Invoke any worker boot hooks so they can get
|
144
227
|
# things in shape before booting the app.
|
145
|
-
|
146
|
-
hooks.each { |h| h.call }
|
228
|
+
@launcher.config.run_hooks :before_worker_boot, index
|
147
229
|
|
148
230
|
server = start_server
|
149
231
|
|
@@ -154,13 +236,33 @@ module Puma
|
|
154
236
|
begin
|
155
237
|
@worker_write << "b#{Process.pid}\n"
|
156
238
|
rescue SystemCallError, IOError
|
157
|
-
STDERR.puts "Master seems to have
|
239
|
+
STDERR.puts "Master seems to have exited, exiting."
|
158
240
|
return
|
159
241
|
end
|
160
242
|
|
243
|
+
Thread.new(@worker_write) do |io|
|
244
|
+
base_payload = "p#{Process.pid}"
|
245
|
+
|
246
|
+
while true
|
247
|
+
sleep 5
|
248
|
+
begin
|
249
|
+
b = server.backlog
|
250
|
+
r = server.running
|
251
|
+
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r} }\n!
|
252
|
+
io << payload
|
253
|
+
rescue IOError
|
254
|
+
break
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
161
259
|
server.run.join
|
162
260
|
|
261
|
+
# Invoke any worker shutdown hooks so they can prevent the worker
|
262
|
+
# exiting until any background operations are completed
|
263
|
+
@launcher.config.run_hooks :before_worker_shutdown, index
|
163
264
|
ensure
|
265
|
+
@worker_write << "t#{Process.pid}\n" rescue nil
|
164
266
|
@worker_write.close
|
165
267
|
end
|
166
268
|
|
@@ -195,37 +297,27 @@ module Puma
|
|
195
297
|
wakeup!
|
196
298
|
end
|
197
299
|
|
300
|
+
def reload_worker_directory
|
301
|
+
if dir = @options[:worker_directory]
|
302
|
+
log "+ Changing to #{dir}"
|
303
|
+
Dir.chdir dir
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
198
307
|
def stats
|
199
|
-
|
308
|
+
old_worker_count = @workers.count { |w| w.phase != @phase }
|
309
|
+
booted_worker_count = @workers.count { |w| w.booted? }
|
310
|
+
worker_status = '[' + @workers.map{ |w| %Q!{ "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
|
311
|
+
%Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
|
200
312
|
end
|
201
313
|
|
202
314
|
def preload?
|
203
315
|
@options[:preload_app]
|
204
316
|
end
|
205
317
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
output_header "cluster"
|
210
|
-
|
211
|
-
log "* Process workers: #{@options[:workers]}"
|
212
|
-
|
213
|
-
if preload?
|
214
|
-
log "* Preloading application"
|
215
|
-
load_and_bind
|
216
|
-
else
|
217
|
-
log "* Phased restart available"
|
218
|
-
|
219
|
-
unless @cli.config.app_configured?
|
220
|
-
error "No application configured, nothing to run"
|
221
|
-
exit 1
|
222
|
-
end
|
223
|
-
|
224
|
-
@cli.binder.parse @options[:binds], self
|
225
|
-
end
|
226
|
-
|
227
|
-
read, @wakeup = Puma::Util.pipe
|
228
|
-
|
318
|
+
# We do this in a separate method to keep the lambad scope
|
319
|
+
# of the signals handlers as small as possible.
|
320
|
+
def setup_signals
|
229
321
|
Signal.trap "SIGCHLD" do
|
230
322
|
wakeup!
|
231
323
|
end
|
@@ -254,6 +346,48 @@ module Puma
|
|
254
346
|
stop
|
255
347
|
end
|
256
348
|
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def run
|
352
|
+
@status = :run
|
353
|
+
|
354
|
+
output_header "cluster"
|
355
|
+
|
356
|
+
log "* Process workers: #{@options[:workers]}"
|
357
|
+
|
358
|
+
before = Thread.list
|
359
|
+
|
360
|
+
if preload?
|
361
|
+
log "* Preloading application"
|
362
|
+
load_and_bind
|
363
|
+
|
364
|
+
after = Thread.list
|
365
|
+
|
366
|
+
if after.size > before.size
|
367
|
+
threads = (after - before)
|
368
|
+
if threads.first.respond_to? :backtrace
|
369
|
+
log "! WARNING: Detected #{after.size-before.size} Thread(s) started in app boot:"
|
370
|
+
threads.each do |t|
|
371
|
+
log "! #{t.inspect} - #{t.backtrace ? t.backtrace.first : ''}"
|
372
|
+
end
|
373
|
+
else
|
374
|
+
log "! WARNING: Detected #{after.size-before.size} Thread(s) started in app boot"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
else
|
378
|
+
log "* Phased restart available"
|
379
|
+
|
380
|
+
unless @launcher.config.app_configured?
|
381
|
+
error "No application configured, nothing to run"
|
382
|
+
exit 1
|
383
|
+
end
|
384
|
+
|
385
|
+
@launcher.binder.parse @options[:binds], self
|
386
|
+
end
|
387
|
+
|
388
|
+
read, @wakeup = Puma::Util.pipe
|
389
|
+
|
390
|
+
setup_signals
|
257
391
|
|
258
392
|
# Used by the workers to detect if the master process dies.
|
259
393
|
# If select says that @check_pipe is ready, it's because the
|
@@ -273,34 +407,49 @@ module Puma
|
|
273
407
|
|
274
408
|
start_control
|
275
409
|
|
276
|
-
@
|
410
|
+
@launcher.write_state
|
277
411
|
|
278
412
|
@master_read, @worker_write = read, @wakeup
|
413
|
+
|
414
|
+
@launcher.config.run_hooks :before_fork, nil
|
415
|
+
|
279
416
|
spawn_workers
|
280
417
|
|
281
418
|
Signal.trap "SIGINT" do
|
282
419
|
stop
|
283
420
|
end
|
284
421
|
|
285
|
-
@
|
422
|
+
@launcher.events.fire_on_booted!
|
286
423
|
|
287
424
|
begin
|
288
425
|
while @status == :run
|
289
426
|
begin
|
290
427
|
res = IO.select([read], nil, nil, 5)
|
291
428
|
|
429
|
+
force_check = false
|
430
|
+
|
292
431
|
if res
|
293
432
|
req = read.read_nonblock(1)
|
294
433
|
|
295
|
-
if req == "
|
296
|
-
|
297
|
-
|
298
|
-
|
434
|
+
next if !req || req == "!"
|
435
|
+
|
436
|
+
result = read.gets
|
437
|
+
pid = result.to_i
|
438
|
+
|
439
|
+
if w = @workers.find { |x| x.pid == pid }
|
440
|
+
case req
|
441
|
+
when "b"
|
299
442
|
w.boot!
|
300
|
-
log "- Worker #{pid} booted, phase: #{w.phase}"
|
301
|
-
|
302
|
-
|
443
|
+
log "- Worker #{w.index} (pid: #{pid}) booted, phase: #{w.phase}"
|
444
|
+
force_check = true
|
445
|
+
when "t"
|
446
|
+
w.dead!
|
447
|
+
force_check = true
|
448
|
+
when "p"
|
449
|
+
w.ping!(result.sub(/^\d+/,'').chomp)
|
303
450
|
end
|
451
|
+
else
|
452
|
+
log "! Out-of-sync worker list, no #{pid} worker"
|
304
453
|
end
|
305
454
|
end
|
306
455
|
|
@@ -309,7 +458,7 @@ module Puma
|
|
309
458
|
@phased_restart = false
|
310
459
|
end
|
311
460
|
|
312
|
-
check_workers
|
461
|
+
check_workers force_check
|
313
462
|
|
314
463
|
rescue Interrupt
|
315
464
|
@status = :stop
|