puma 2.0.0.b4-java → 2.0.0.b7-java
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.
- data/History.txt +53 -0
- data/Manifest.txt +8 -3
- data/README.md +36 -5
- data/Rakefile +1 -1
- data/lib/puma/binder.rb +1 -1
- data/lib/puma/capistrano.rb +14 -12
- data/lib/puma/cli.rb +166 -25
- data/lib/puma/client.rb +9 -1
- data/lib/puma/configuration.rb +54 -13
- data/lib/puma/const.rb +7 -1
- data/lib/puma/jruby_restart.rb +4 -4
- data/lib/puma/minissl.rb +94 -92
- data/lib/puma/rack_default.rb +7 -0
- data/lib/puma/reactor.rb +28 -12
- data/lib/puma/server.rb +56 -27
- data/lib/puma/util.rb +9 -0
- data/puma.gemspec +10 -10
- data/test/test_config.rb +1 -1
- data/test/test_minissl.rb +5 -2
- data/test/test_puma_server.rb +37 -0
- data/tools/jungle/{README.md → init.d/README.md} +0 -0
- data/tools/jungle/{puma → init.d/puma} +0 -0
- data/tools/jungle/{run-puma → init.d/run-puma} +0 -0
- data/tools/jungle/upstart/README.md +61 -0
- data/tools/jungle/upstart/puma-manager.conf +31 -0
- data/tools/jungle/upstart/puma.conf +52 -0
- metadata +16 -8
data/History.txt
CHANGED
@@ -1,3 +1,56 @@
|
|
1
|
+
=== 2.0.0.b7 / 2013-03-18
|
2
|
+
|
3
|
+
* 5 minor enhancements:
|
4
|
+
|
5
|
+
* Add -q option for :start
|
6
|
+
* Add -V, --version
|
7
|
+
* Add default Rack handler helper
|
8
|
+
* Upstart support
|
9
|
+
* Set worker directory from configuration file
|
10
|
+
|
11
|
+
* 12 bug fixes:
|
12
|
+
|
13
|
+
* Close the binder in the right place. Fixes #192
|
14
|
+
* Handle early term in workers. Fixes #206
|
15
|
+
* Make sure that the default port is 80 when the request doesn't include HTTP_X_FORWARDED_PROTO.
|
16
|
+
* Prevent Errno::EBADF errors on restart when running ruby 2.0
|
17
|
+
* Record the proper @master_pid
|
18
|
+
* Respect the header HTTP_X_FORWARDED_PROTO when the host doesn't include a port number.
|
19
|
+
* Retry EAGAIN/EWOULDBLOCK during syswrite
|
20
|
+
* Run exec properly to restart. Fixes #154
|
21
|
+
* Set Rack run_once to false
|
22
|
+
* Syncronize all access to @timeouts. Fixes #208
|
23
|
+
* Write out the state post-daemonize. Fixes #189
|
24
|
+
* Prevent crash when all workers are gone
|
25
|
+
|
26
|
+
=== 2.0.0.b6 / 2013-02-06
|
27
|
+
|
28
|
+
* 2 minor enhancements:
|
29
|
+
|
30
|
+
* Add hook for running when a worker boots
|
31
|
+
* Advertise the Configuration object for apps to use.
|
32
|
+
|
33
|
+
* 1 bug fix:
|
34
|
+
|
35
|
+
* Change directory in working during upgrade. Fixes #185
|
36
|
+
|
37
|
+
=== 2.0.0.b5 / 2013-02-05
|
38
|
+
|
39
|
+
* 2 major features:
|
40
|
+
* Add phased worker upgrade
|
41
|
+
* Add support for the rack hijack protocol
|
42
|
+
|
43
|
+
* 2 minor features:
|
44
|
+
* Add -R to specify the restart command
|
45
|
+
* Add config file option to specify the restart command
|
46
|
+
|
47
|
+
* 5 bug fixes:
|
48
|
+
* Cleanup pipes properly. Fixes #182
|
49
|
+
* Daemonize earlier so that we don't lose app threads. Fixes #183
|
50
|
+
* Drain the notification pipe. Fixes #176, thanks @cryo28
|
51
|
+
* Move write_pid to after we daemonize. Fixes #180
|
52
|
+
* Redirect IO properly and emit message for checkpointing
|
53
|
+
|
1
54
|
=== 2.0.0.b4 / 2012-12-12
|
2
55
|
|
3
56
|
* 4 bug fixes:
|
data/Manifest.txt
CHANGED
@@ -44,12 +44,17 @@ lib/puma/java_io_buffer.rb
|
|
44
44
|
lib/puma/jruby_restart.rb
|
45
45
|
lib/puma/minissl.rb
|
46
46
|
lib/puma/null_io.rb
|
47
|
+
lib/puma/rack_default.rb
|
47
48
|
lib/puma/rack_patch.rb
|
48
49
|
lib/puma/reactor.rb
|
49
50
|
lib/puma/server.rb
|
50
51
|
lib/puma/thread_pool.rb
|
52
|
+
lib/puma/util.rb
|
51
53
|
lib/rack/handler/puma.rb
|
52
54
|
puma.gemspec
|
53
|
-
tools/jungle/README.md
|
54
|
-
tools/jungle/puma
|
55
|
-
tools/jungle/run-puma
|
55
|
+
tools/jungle/init.d/README.md
|
56
|
+
tools/jungle/init.d/puma
|
57
|
+
tools/jungle/init.d/run-puma
|
58
|
+
tools/jungle/upstart/README.md
|
59
|
+
tools/jungle/upstart/puma-manager.conf
|
60
|
+
tools/jungle/upstart/puma.conf
|
data/README.md
CHANGED
@@ -66,7 +66,7 @@ Puma provides numerous options for controlling the operation of the server. Cons
|
|
66
66
|
Puma utilizes a dynamic thread pool which you can modify. You can set the minimum and maximum number of threads that are available in the pool with the `-t` (or `--threads`) flag:
|
67
67
|
|
68
68
|
$ puma -t 8:32
|
69
|
-
|
69
|
+
|
70
70
|
Puma will automatically scale the number of threads based on how much traffic is present. The current default is `0:16`. Feel free to experiment, but be careful not to set the number of maximum threads to a very large number, as you may exhaust resources on the system (or hit resource limits).
|
71
71
|
|
72
72
|
### Binding TCP / Sockets
|
@@ -95,9 +95,21 @@ Puma comes with a builtin status/control app that can be used query and control
|
|
95
95
|
|
96
96
|
This directs puma to start the control server on localhost port 9293. Additionally, all requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out https://github.com/puma/puma/blob/master/lib/puma/app/status.rb to see what the app has available.
|
97
97
|
|
98
|
+
### Configuration file
|
99
|
+
|
100
|
+
You can also provide a configuration file which puma will use:
|
101
|
+
|
102
|
+
$ puma --config /path/to/config
|
103
|
+
|
104
|
+
or
|
105
|
+
|
106
|
+
$ puma -C /path/to/config
|
107
|
+
|
108
|
+
Take the following [sample configuration](https://github.com/puma/puma/blob/master/examples/config.rb) as inspiration or check out [configuration.rb](https://github.com/puma/puma/blob/master/lib/puma/configuration.rb#L138) to see all available options.
|
109
|
+
|
98
110
|
## Restart
|
99
111
|
|
100
|
-
Puma includes the ability to restart itself, allowing for new versions to be easily upgraded to. When available (
|
112
|
+
Puma includes the ability to restart itself, allowing for new versions to be easily upgraded to. When available (MRI, Rubinius, JRuby), puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
|
101
113
|
|
102
114
|
To perform a restart, there are 2 builtin mechanism:
|
103
115
|
|
@@ -120,7 +132,7 @@ If you start puma with `-S some/path` then you can pass that same path to the `p
|
|
120
132
|
|
121
133
|
$ pumactl -S some/path command
|
122
134
|
|
123
|
-
or
|
135
|
+
or
|
124
136
|
|
125
137
|
$ pumactl -C url -T token command
|
126
138
|
|
@@ -128,9 +140,28 @@ will cause the server to perform a restart. `pumactl` is a simple CLI frontend t
|
|
128
140
|
|
129
141
|
Allowed commands: status, restart, halt, stop
|
130
142
|
|
131
|
-
## Managing multiple Pumas / init.d
|
143
|
+
## Managing multiple Pumas / init.d / upstart scripts
|
144
|
+
|
145
|
+
If you want an easy way to manage multiple scripts at once check [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for init.d and upstart scripts.
|
146
|
+
|
147
|
+
## Capistrano deployment
|
148
|
+
|
149
|
+
Puma has included Capistrano [deploy script](https://github.com/plentz/puma/blob/master/lib/puma/capistrano.rb), you just need require that:
|
150
|
+
|
151
|
+
config/deploy.rb
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
require 'puma/capistrano'
|
155
|
+
```
|
156
|
+
|
157
|
+
and then
|
158
|
+
|
159
|
+
```bash
|
160
|
+
$ bunde exec cap puma:start
|
161
|
+
$ bunde exec cap puma:restart
|
162
|
+
$ bunde exec cap puma:stop
|
163
|
+
```
|
132
164
|
|
133
|
-
If you want an easy way to manage multiple scripts at once check [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for an init.d script.
|
134
165
|
|
135
166
|
## License
|
136
167
|
|
data/Rakefile
CHANGED
data/lib/puma/binder.rb
CHANGED
@@ -15,7 +15,7 @@ module Puma
|
|
15
15
|
"rack.errors".freeze => events.stderr,
|
16
16
|
"rack.multithread".freeze => true,
|
17
17
|
"rack.multiprocess".freeze => false,
|
18
|
-
"rack.run_once".freeze =>
|
18
|
+
"rack.run_once".freeze => false,
|
19
19
|
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
|
20
20
|
|
21
21
|
# Rack blows up if this is an empty string, and Rack::Lint
|
data/lib/puma/capistrano.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
1
|
Capistrano::Configuration.instance.load do
|
2
|
-
after
|
3
|
-
after
|
4
|
-
after
|
2
|
+
after 'deploy:stop', 'puma:stop'
|
3
|
+
after 'deploy:start', 'puma:start'
|
4
|
+
after 'deploy:restart', 'puma:restart'
|
5
5
|
|
6
|
-
_cset(:
|
6
|
+
_cset(:puma_cmd) { "#{fetch(:bundle_cmd, 'bundle')} exec puma" }
|
7
|
+
_cset(:pumactl_cmd) { "#{fetch(:bundle_cmd, 'bundle')} exec pumactl" }
|
8
|
+
_cset(:puma_state) { "#{shared_path}/sockets/puma.state" }
|
9
|
+
_cset(:puma_role) { :app }
|
7
10
|
|
8
11
|
namespace :puma do
|
9
|
-
desc
|
12
|
+
desc 'Start puma'
|
10
13
|
task :start, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
|
11
|
-
puma_env = fetch(:rack_env, fetch(:rails_env,
|
12
|
-
run "cd #{current_path} && #{fetch(:
|
14
|
+
puma_env = fetch(:rack_env, fetch(:rails_env, 'production'))
|
15
|
+
run "cd #{current_path} && #{fetch(:puma_cmd)} -q -d -e #{puma_env} -b 'unix://#{shared_path}/sockets/puma.sock' -S #{fetch(:puma_state)} --control 'unix://#{shared_path}/sockets/pumactl.sock'", :pty => false
|
13
16
|
end
|
14
17
|
|
15
|
-
desc
|
18
|
+
desc 'Stop puma'
|
16
19
|
task :stop, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
|
17
|
-
run "cd #{current_path} && #{fetch(:
|
20
|
+
run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S fetch(:puma_state) stop"
|
18
21
|
end
|
19
22
|
|
20
|
-
desc
|
23
|
+
desc 'Restart puma'
|
21
24
|
task :restart, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
|
22
|
-
run "cd #{current_path} && #{fetch(:
|
25
|
+
run "cd #{current_path} && #{fetch(:pumactl_cmd)} -S fetch(:puma_state) restart"
|
23
26
|
end
|
24
|
-
|
25
27
|
end
|
26
28
|
end
|
data/lib/puma/cli.rb
CHANGED
@@ -7,6 +7,7 @@ require 'puma/configuration'
|
|
7
7
|
require 'puma/binder'
|
8
8
|
require 'puma/detect'
|
9
9
|
require 'puma/daemon_ext'
|
10
|
+
require 'puma/util'
|
10
11
|
|
11
12
|
require 'rack/commonlogger'
|
12
13
|
require 'rack/utils'
|
@@ -27,6 +28,7 @@ module Puma
|
|
27
28
|
@stdout = stdout
|
28
29
|
@stderr = stderr
|
29
30
|
|
31
|
+
@phase = 0
|
30
32
|
@workers = []
|
31
33
|
|
32
34
|
@events = Events.new @stdout, @stderr
|
@@ -35,6 +37,10 @@ module Puma
|
|
35
37
|
@status = nil
|
36
38
|
|
37
39
|
@restart = false
|
40
|
+
@phased_state = :idle
|
41
|
+
|
42
|
+
@io_redirected = false
|
43
|
+
|
38
44
|
|
39
45
|
ENV['NEWRELIC_DISPATCHER'] ||= "puma"
|
40
46
|
|
@@ -60,6 +66,7 @@ module Puma
|
|
60
66
|
|
61
67
|
if s_env.ino == s_pwd.ino and s_env.dev == s_pwd.dev
|
62
68
|
@restart_dir = dir
|
69
|
+
@options[:worker_directory] = dir
|
63
70
|
end
|
64
71
|
end
|
65
72
|
|
@@ -82,6 +89,10 @@ module Puma
|
|
82
89
|
arg0 = [Gem.ruby, "-S", $0]
|
83
90
|
end
|
84
91
|
|
92
|
+
# Detect and reinject -Ilib from the command line
|
93
|
+
lib = File.expand_path "lib"
|
94
|
+
arg0[1,0] = ["-I", lib] if $:[0] == lib
|
95
|
+
|
85
96
|
@restart_argv = arg0 + ARGV
|
86
97
|
end
|
87
98
|
end
|
@@ -104,10 +115,12 @@ module Puma
|
|
104
115
|
end
|
105
116
|
|
106
117
|
require 'puma/jruby_restart'
|
107
|
-
JRubyRestart.chdir_exec(@restart_dir,
|
118
|
+
JRubyRestart.chdir_exec(@restart_dir, @restart_argv)
|
108
119
|
else
|
120
|
+
redirects = {}
|
109
121
|
@binder.listeners.each_with_index do |(l,io),i|
|
110
122
|
ENV["PUMA_INHERIT_#{i}"] = "#{io.to_i}:#{l}"
|
123
|
+
redirects[io.to_i] = io.to_i
|
111
124
|
end
|
112
125
|
|
113
126
|
if cmd = @options[:restart_cmd]
|
@@ -117,6 +130,8 @@ module Puma
|
|
117
130
|
end
|
118
131
|
|
119
132
|
Dir.chdir @restart_dir
|
133
|
+
|
134
|
+
argv += [redirects] unless RUBY_VERSION < '1.9'
|
120
135
|
Kernel.exec(*argv)
|
121
136
|
end
|
122
137
|
end
|
@@ -164,6 +179,7 @@ module Puma
|
|
164
179
|
:binds => [],
|
165
180
|
:workers => 0,
|
166
181
|
:daemon => false,
|
182
|
+
:worker_boot => [],
|
167
183
|
:environment => "development"
|
168
184
|
}
|
169
185
|
|
@@ -201,6 +217,7 @@ module Puma
|
|
201
217
|
|
202
218
|
o.on "--dir DIR", "Change to DIR before starting" do |d|
|
203
219
|
@options[:directory] = d.to_s
|
220
|
+
@options[:worker_directory] = d.to_s
|
204
221
|
end
|
205
222
|
|
206
223
|
o.on "-e", "--environment ENVIRONMENT",
|
@@ -225,7 +242,7 @@ module Puma
|
|
225
242
|
@options[:quiet] = true
|
226
243
|
end
|
227
244
|
|
228
|
-
o.on "--restart-cmd CMD",
|
245
|
+
o.on "-R", "--restart-cmd CMD",
|
229
246
|
"The puma command to run during a hot restart",
|
230
247
|
"Default: inferred" do |cmd|
|
231
248
|
@options[:restart_cmd] = cmd
|
@@ -246,6 +263,11 @@ module Puma
|
|
246
263
|
end
|
247
264
|
end
|
248
265
|
|
266
|
+
o.on "-V", "--version", "Print the version information" do
|
267
|
+
puts "puma version #{Puma::Const::VERSION}"
|
268
|
+
exit 1
|
269
|
+
end
|
270
|
+
|
249
271
|
o.on "-w", "--workers COUNT",
|
250
272
|
"Activate cluster mode: How many worker processes to create" do |arg|
|
251
273
|
unsupported "-w not supported on JRuby and Windows",
|
@@ -291,13 +313,16 @@ module Puma
|
|
291
313
|
end
|
292
314
|
|
293
315
|
def write_state
|
316
|
+
write_pid
|
317
|
+
|
294
318
|
require 'yaml'
|
295
319
|
|
296
320
|
if path = @options[:state]
|
297
321
|
state = { "pid" => Process.pid }
|
298
322
|
|
299
323
|
cfg = @config.dup
|
300
|
-
|
324
|
+
|
325
|
+
[ :logger, :worker_boot, :on_restart ].each { |o| cfg.options.delete o }
|
301
326
|
|
302
327
|
state["config"] = cfg
|
303
328
|
|
@@ -316,6 +341,10 @@ module Puma
|
|
316
341
|
end
|
317
342
|
|
318
343
|
@config = Puma::Configuration.new @options
|
344
|
+
|
345
|
+
# Advertise the Configuration
|
346
|
+
Puma.cli_config = @config
|
347
|
+
|
319
348
|
@config.load
|
320
349
|
end
|
321
350
|
|
@@ -333,11 +362,14 @@ module Puma
|
|
333
362
|
append = @options[:redirect_append]
|
334
363
|
|
335
364
|
if stdout
|
365
|
+
@io_redirected = true
|
336
366
|
STDOUT.reopen stdout, (append ? "a" : "w")
|
367
|
+
STDOUT.puts "=== puma startup: #{Time.now} ==="
|
337
368
|
end
|
338
369
|
|
339
370
|
if stderr
|
340
|
-
|
371
|
+
STDERR.reopen stderr, (append ? "a" : "w")
|
372
|
+
STDERR.puts "=== puma startup: #{Time.now} ==="
|
341
373
|
end
|
342
374
|
end
|
343
375
|
|
@@ -364,9 +396,6 @@ module Puma
|
|
364
396
|
|
365
397
|
set_rack_environment
|
366
398
|
|
367
|
-
write_pid
|
368
|
-
write_state
|
369
|
-
|
370
399
|
if clustered
|
371
400
|
run_cluster
|
372
401
|
else
|
@@ -384,6 +413,12 @@ module Puma
|
|
384
413
|
|
385
414
|
@binder.parse @options[:binds], self
|
386
415
|
|
416
|
+
if @options[:daemon]
|
417
|
+
Process.daemon(true, @io_redirected)
|
418
|
+
end
|
419
|
+
|
420
|
+
write_state
|
421
|
+
|
387
422
|
server = Puma::Server.new @config.app, @events
|
388
423
|
server.binder = @binder
|
389
424
|
server.min_threads = min_t
|
@@ -441,9 +476,7 @@ module Puma
|
|
441
476
|
log "*** Sorry signal SIGTERM not implemented, gracefully stopping feature disabled!"
|
442
477
|
end
|
443
478
|
|
444
|
-
|
445
|
-
Process.daemon(true)
|
446
|
-
else
|
479
|
+
unless @options[:daemon]
|
447
480
|
log "Use Ctrl-C to stop"
|
448
481
|
end
|
449
482
|
|
@@ -469,31 +502,51 @@ module Puma
|
|
469
502
|
end
|
470
503
|
end
|
471
504
|
|
472
|
-
def worker
|
505
|
+
def worker(upgrade)
|
473
506
|
$0 = "puma: cluster worker: #{@master_pid}"
|
474
507
|
Signal.trap "SIGINT", "IGNORE"
|
475
508
|
|
509
|
+
@master_read.close
|
476
510
|
@suicide_pipe.close
|
477
511
|
|
478
512
|
Thread.new do
|
479
513
|
IO.select [@check_pipe]
|
480
|
-
log "! Detected parent died,
|
514
|
+
log "! Detected parent died, dying"
|
481
515
|
exit! 1
|
482
516
|
end
|
483
517
|
|
518
|
+
# Be sure to change the directory again before loading
|
519
|
+
# the app. This way we can pick up new code.
|
520
|
+
if upgrade
|
521
|
+
if dir = @options[:worker_directory]
|
522
|
+
log "+ Changing to #{dir}"
|
523
|
+
Dir.chdir dir
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
# Invoke any worker boot hooks so they can get
|
528
|
+
# things in shape before booting the app.
|
529
|
+
hooks = @options[:worker_boot]
|
530
|
+
hooks.each { |h| h.call }
|
531
|
+
|
484
532
|
min_t = @options[:min_threads]
|
485
533
|
max_t = @options[:max_threads]
|
486
534
|
|
487
535
|
server = Puma::Server.new @config.app, @events
|
488
536
|
server.min_threads = min_t
|
489
537
|
server.max_threads = max_t
|
490
|
-
server.
|
538
|
+
server.inherit_binder @binder
|
491
539
|
|
492
540
|
Signal.trap "SIGTERM" do
|
493
541
|
server.stop
|
494
542
|
end
|
495
543
|
|
544
|
+
@worker_write << "b#{Process.pid}\n"
|
545
|
+
|
496
546
|
server.run.join
|
547
|
+
|
548
|
+
ensure
|
549
|
+
@worker_write.close
|
497
550
|
end
|
498
551
|
|
499
552
|
def stop_workers
|
@@ -509,12 +562,27 @@ module Puma
|
|
509
562
|
end
|
510
563
|
end
|
511
564
|
|
565
|
+
def start_phased_restart
|
566
|
+
@phase += 1
|
567
|
+
log "- Starting phased worker restart, phase: #{@phase}"
|
568
|
+
end
|
569
|
+
|
512
570
|
class Worker
|
513
|
-
def initialize(pid)
|
571
|
+
def initialize(pid, phase)
|
514
572
|
@pid = pid
|
573
|
+
@phase = phase
|
574
|
+
@stage = :started
|
515
575
|
end
|
516
576
|
|
517
|
-
attr_reader :pid
|
577
|
+
attr_reader :pid, :phase
|
578
|
+
|
579
|
+
def booted?
|
580
|
+
@stage == :booted
|
581
|
+
end
|
582
|
+
|
583
|
+
def boot!
|
584
|
+
@stage = :booted
|
585
|
+
end
|
518
586
|
|
519
587
|
def term
|
520
588
|
begin
|
@@ -527,15 +595,25 @@ module Puma
|
|
527
595
|
def spawn_workers
|
528
596
|
diff = @options[:workers] - @workers.size
|
529
597
|
|
598
|
+
upgrade = (@phased_state == :waiting)
|
599
|
+
|
530
600
|
diff.times do
|
531
|
-
pid = fork { worker }
|
601
|
+
pid = fork { worker(upgrade) }
|
532
602
|
debug "Spawned worker: #{pid}"
|
533
|
-
@workers << Worker.new(pid)
|
603
|
+
@workers << Worker.new(pid, @phase)
|
604
|
+
end
|
605
|
+
|
606
|
+
if diff > 0
|
607
|
+
@phased_state = :idle
|
534
608
|
end
|
535
609
|
end
|
536
610
|
|
611
|
+
def all_workers_booted?
|
612
|
+
@workers.count { |w| !w.booted? } == 0
|
613
|
+
end
|
614
|
+
|
537
615
|
def check_workers
|
538
|
-
while
|
616
|
+
while @workers.any?
|
539
617
|
pid = Process.waitpid(-1, Process::WNOHANG)
|
540
618
|
break unless pid
|
541
619
|
|
@@ -543,6 +621,20 @@ module Puma
|
|
543
621
|
end
|
544
622
|
|
545
623
|
spawn_workers
|
624
|
+
|
625
|
+
if @phased_state == :idle && all_workers_booted?
|
626
|
+
# If we're running at proper capacity, check to see if
|
627
|
+
# we need to phase any workers out (which will restart
|
628
|
+
# in the right phase).
|
629
|
+
#
|
630
|
+
w = @workers.find { |x| x.phase != @phase }
|
631
|
+
|
632
|
+
if w
|
633
|
+
@phased_state = :waiting
|
634
|
+
log "- Stopping #{w.pid} for phased upgrade..."
|
635
|
+
w.term
|
636
|
+
end
|
637
|
+
end
|
546
638
|
end
|
547
639
|
|
548
640
|
def run_cluster
|
@@ -553,9 +645,7 @@ module Puma
|
|
553
645
|
|
554
646
|
@binder.parse @options[:binds], self
|
555
647
|
|
556
|
-
|
557
|
-
|
558
|
-
read, write = IO.pipe
|
648
|
+
read, write = Puma::Util.pipe
|
559
649
|
|
560
650
|
Signal.trap "SIGCHLD" do
|
561
651
|
write.write "!"
|
@@ -572,9 +662,29 @@ module Puma
|
|
572
662
|
rescue Exception
|
573
663
|
end
|
574
664
|
|
665
|
+
master_pid = Process.pid
|
666
|
+
|
575
667
|
begin
|
576
668
|
Signal.trap "SIGTERM" do
|
577
|
-
|
669
|
+
# The worker installs there own SIGTERM when booted.
|
670
|
+
# Until then, this is run by the worker and the worker
|
671
|
+
# should just exit if they get it.
|
672
|
+
if Process.pid != master_pid
|
673
|
+
log "Early termination of worker"
|
674
|
+
exit! 0
|
675
|
+
else
|
676
|
+
stop = true
|
677
|
+
write.write "!"
|
678
|
+
end
|
679
|
+
end
|
680
|
+
rescue Exception
|
681
|
+
end
|
682
|
+
|
683
|
+
phased_restart = false
|
684
|
+
|
685
|
+
begin
|
686
|
+
Signal.trap "SIGUSR1" do
|
687
|
+
phased_restart = true
|
578
688
|
write.write "!"
|
579
689
|
end
|
580
690
|
rescue Exception
|
@@ -585,16 +695,21 @@ module Puma
|
|
585
695
|
# master has exited and @suicide_pipe has been automatically
|
586
696
|
# closed.
|
587
697
|
#
|
588
|
-
@check_pipe, @suicide_pipe =
|
698
|
+
@check_pipe, @suicide_pipe = Puma::Util.pipe
|
589
699
|
|
590
700
|
if @options[:daemon]
|
591
|
-
Process.daemon(true)
|
701
|
+
Process.daemon(true, @io_redirected)
|
592
702
|
else
|
593
703
|
log "Use Ctrl-C to stop"
|
594
704
|
end
|
595
705
|
|
706
|
+
@master_pid = Process.pid
|
707
|
+
|
596
708
|
redirect_io
|
597
709
|
|
710
|
+
write_state
|
711
|
+
|
712
|
+
@master_read, @worker_write = read, write
|
598
713
|
spawn_workers
|
599
714
|
|
600
715
|
Signal.trap "SIGINT" do
|
@@ -605,8 +720,30 @@ module Puma
|
|
605
720
|
begin
|
606
721
|
while !stop
|
607
722
|
begin
|
608
|
-
IO.select([read], nil, nil, 5)
|
723
|
+
res = IO.select([read], nil, nil, 5)
|
724
|
+
|
725
|
+
if res
|
726
|
+
req = read.read_nonblock(1)
|
727
|
+
|
728
|
+
if req == "b"
|
729
|
+
pid = read.gets.to_i
|
730
|
+
w = @workers.find { |x| x.pid == pid }
|
731
|
+
if w
|
732
|
+
w.boot!
|
733
|
+
log "- Worker #{pid} booted, phase: #{w.phase}"
|
734
|
+
else
|
735
|
+
log "! Out-of-sync worker list, no #{pid} worker"
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
609
740
|
check_workers
|
741
|
+
|
742
|
+
if phased_restart
|
743
|
+
start_phased_restart
|
744
|
+
phased_restart = false
|
745
|
+
end
|
746
|
+
|
610
747
|
rescue Interrupt
|
611
748
|
stop = true
|
612
749
|
end
|
@@ -615,6 +752,10 @@ module Puma
|
|
615
752
|
stop_workers
|
616
753
|
ensure
|
617
754
|
delete_pidfile
|
755
|
+
@check_pipe.close
|
756
|
+
@suicide_pipe.close
|
757
|
+
read.close
|
758
|
+
write.close
|
618
759
|
end
|
619
760
|
|
620
761
|
if @restart
|