puma 5.6.5 → 6.4.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 +338 -14
- data/LICENSE +0 -0
- data/README.md +79 -29
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +34 -0
- data/docs/deployment.md +0 -0
- 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 +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +0 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +0 -0
- data/docs/stats.md +0 -0
- data/docs/systemd.md +3 -6
- 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 +16 -9
- 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 +127 -19
- 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 +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +50 -53
- data/lib/puma/cli.rb +16 -18
- data/lib/puma/client.rb +100 -26
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +102 -40
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +77 -59
- data/lib/puma/const.rb +129 -92
- data/lib/puma/control_cli.rb +15 -11
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +250 -56
- data/lib/puma/error_logger.rb +18 -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/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +102 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +26 -12
- data/lib/puma/minissl.rb +104 -11
- data/lib/puma/null_io.rb +16 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -170
- data/lib/puma/runner.rb +56 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +137 -89
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +3 -6
- data/lib/puma/thread_pool.rb +57 -19
- data/lib/puma/util.rb +0 -11
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +2 -2
- data/tools/trickletest.rb +0 -0
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/cluster.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require 'time'
|
3
|
+
require_relative 'runner'
|
4
|
+
require_relative 'util'
|
5
|
+
require_relative 'plugin'
|
6
|
+
require_relative 'cluster/worker_handle'
|
7
|
+
require_relative 'cluster/worker'
|
10
8
|
|
11
9
|
module Puma
|
12
10
|
# This class is instantiated by the `Puma::Launcher` and used
|
@@ -17,8 +15,8 @@ module Puma
|
|
17
15
|
# via the `spawn_workers` method call. Each worker will have it's own
|
18
16
|
# instance of a `Puma::Server`.
|
19
17
|
class Cluster < Runner
|
20
|
-
def initialize(
|
21
|
-
super
|
18
|
+
def initialize(launcher)
|
19
|
+
super(launcher)
|
22
20
|
|
23
21
|
@phase = 0
|
24
22
|
@workers = []
|
@@ -27,6 +25,10 @@ module Puma
|
|
27
25
|
@phased_restart = false
|
28
26
|
end
|
29
27
|
|
28
|
+
# Returns the list of cluster worker handles.
|
29
|
+
# @return [Array<Puma::Cluster::WorkerHandle>]
|
30
|
+
attr_reader :workers
|
31
|
+
|
30
32
|
def stop_workers
|
31
33
|
log "- Gracefully shutting down workers..."
|
32
34
|
@workers.each { |x| x.term }
|
@@ -83,16 +85,14 @@ module Puma
|
|
83
85
|
@workers << WorkerHandle.new(idx, pid, @phase, @options)
|
84
86
|
end
|
85
87
|
|
86
|
-
if @options[:fork_worker] &&
|
87
|
-
@workers.all? {|x| x.phase == @phase}
|
88
|
-
|
88
|
+
if @options[:fork_worker] && all_workers_in_phase?
|
89
89
|
@fork_writer << "0\n"
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
93
|
# @version 5.0.0
|
94
94
|
def spawn_worker(idx, master)
|
95
|
-
@
|
95
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer)
|
96
96
|
|
97
97
|
pid = fork { worker(idx, master) }
|
98
98
|
if !pid
|
@@ -101,7 +101,7 @@ module Puma
|
|
101
101
|
exit! 1
|
102
102
|
end
|
103
103
|
|
104
|
-
@
|
104
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer)
|
105
105
|
pid
|
106
106
|
end
|
107
107
|
|
@@ -146,10 +146,22 @@ module Puma
|
|
146
146
|
idx
|
147
147
|
end
|
148
148
|
|
149
|
+
def worker_at(idx)
|
150
|
+
@workers.find { |w| w.index == idx }
|
151
|
+
end
|
152
|
+
|
149
153
|
def all_workers_booted?
|
150
154
|
@workers.count { |w| !w.booted? } == 0
|
151
155
|
end
|
152
156
|
|
157
|
+
def all_workers_in_phase?
|
158
|
+
@workers.all? { |w| w.phase == @phase }
|
159
|
+
end
|
160
|
+
|
161
|
+
def all_workers_idle_timed_out?
|
162
|
+
(@workers.map(&:pid) - idle_timed_out_worker_pids).empty?
|
163
|
+
end
|
164
|
+
|
153
165
|
def check_workers
|
154
166
|
return if @next_check >= Time.now
|
155
167
|
|
@@ -176,10 +188,10 @@ module Puma
|
|
176
188
|
end
|
177
189
|
end
|
178
190
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
].compact.min
|
191
|
+
t = @workers.reject(&:term?)
|
192
|
+
t.map!(&:ping_timeout)
|
193
|
+
|
194
|
+
@next_check = [t.min, @next_check].compact.min
|
183
195
|
end
|
184
196
|
|
185
197
|
def worker(index, master)
|
@@ -209,8 +221,8 @@ module Puma
|
|
209
221
|
stop
|
210
222
|
end
|
211
223
|
|
212
|
-
def phased_restart
|
213
|
-
return false if @options[:preload_app]
|
224
|
+
def phased_restart(refork = false)
|
225
|
+
return false if @options[:preload_app] && !refork
|
214
226
|
|
215
227
|
@phased_restart = true
|
216
228
|
wakeup!
|
@@ -226,7 +238,7 @@ module Puma
|
|
226
238
|
def stop_blocked
|
227
239
|
@status = :stop if @status == :run
|
228
240
|
wakeup!
|
229
|
-
@control
|
241
|
+
@control&.stop true
|
230
242
|
Process.waitall
|
231
243
|
end
|
232
244
|
|
@@ -248,24 +260,24 @@ module Puma
|
|
248
260
|
old_worker_count = @workers.count { |w| w.phase != @phase }
|
249
261
|
worker_status = @workers.map do |w|
|
250
262
|
{
|
251
|
-
started_at: w.started_at
|
263
|
+
started_at: utc_iso8601(w.started_at),
|
252
264
|
pid: w.pid,
|
253
265
|
index: w.index,
|
254
266
|
phase: w.phase,
|
255
267
|
booted: w.booted?,
|
256
|
-
last_checkin: w.last_checkin
|
268
|
+
last_checkin: utc_iso8601(w.last_checkin),
|
257
269
|
last_status: w.last_status,
|
258
270
|
}
|
259
271
|
end
|
260
272
|
|
261
273
|
{
|
262
|
-
started_at: @started_at
|
274
|
+
started_at: utc_iso8601(@started_at),
|
263
275
|
workers: @workers.size,
|
264
276
|
phase: @phase,
|
265
277
|
booted_workers: worker_status.count { |w| w[:booted] },
|
266
278
|
old_workers: old_worker_count,
|
267
279
|
worker_status: worker_status,
|
268
|
-
}
|
280
|
+
}.merge(super)
|
269
281
|
end
|
270
282
|
|
271
283
|
def preload?
|
@@ -274,10 +286,10 @@ module Puma
|
|
274
286
|
|
275
287
|
# @version 5.0.0
|
276
288
|
def fork_worker!
|
277
|
-
if (worker =
|
289
|
+
if (worker = worker_at 0)
|
278
290
|
worker.phase += 1
|
279
291
|
end
|
280
|
-
phased_restart
|
292
|
+
phased_restart(true)
|
281
293
|
end
|
282
294
|
|
283
295
|
# We do this in a separate method to keep the lambda scope
|
@@ -290,7 +302,7 @@ module Puma
|
|
290
302
|
|
291
303
|
# Auto-fork after the specified number of requests.
|
292
304
|
if (fork_requests = @options[:fork_worker].to_i) > 0
|
293
|
-
@
|
305
|
+
@events.register(:ping!) do |w|
|
294
306
|
fork_worker! if w.index == 0 &&
|
295
307
|
w.phase == 0 &&
|
296
308
|
w.last_status[:requests_count] >= fork_requests
|
@@ -336,6 +348,8 @@ module Puma
|
|
336
348
|
def run
|
337
349
|
@status = :run
|
338
350
|
|
351
|
+
@idle_workers = {}
|
352
|
+
|
339
353
|
output_header "cluster"
|
340
354
|
|
341
355
|
# This is aligned with the output from Runner, see Runner#output_header
|
@@ -372,12 +386,12 @@ module Puma
|
|
372
386
|
else
|
373
387
|
log "* Restarts: (\u2714) hot (\u2714) phased"
|
374
388
|
|
375
|
-
unless @
|
389
|
+
unless @config.app_configured?
|
376
390
|
error "No application configured, nothing to run"
|
377
391
|
exit 1
|
378
392
|
end
|
379
393
|
|
380
|
-
@launcher.binder.parse @options[:binds]
|
394
|
+
@launcher.binder.parse @options[:binds]
|
381
395
|
end
|
382
396
|
|
383
397
|
read, @wakeup = Puma::Util.pipe
|
@@ -409,8 +423,9 @@ module Puma
|
|
409
423
|
|
410
424
|
@master_read, @worker_write = read, @wakeup
|
411
425
|
|
412
|
-
@
|
413
|
-
|
426
|
+
@options[:worker_write] = @worker_write
|
427
|
+
|
428
|
+
@config.run_hooks(:before_fork, nil, @log_writer)
|
414
429
|
|
415
430
|
spawn_workers
|
416
431
|
|
@@ -425,6 +440,11 @@ module Puma
|
|
425
440
|
|
426
441
|
while @status == :run
|
427
442
|
begin
|
443
|
+
if all_workers_idle_timed_out?
|
444
|
+
log "- All workers reached idle timeout"
|
445
|
+
break
|
446
|
+
end
|
447
|
+
|
428
448
|
if @phased_restart
|
429
449
|
start_phased_restart
|
430
450
|
@phased_restart = false
|
@@ -445,7 +465,7 @@ module Puma
|
|
445
465
|
|
446
466
|
if req == "b" || req == "f"
|
447
467
|
pid, idx = result.split(':').map(&:to_i)
|
448
|
-
w =
|
468
|
+
w = worker_at idx
|
449
469
|
w.pid = pid if w.pid.nil?
|
450
470
|
end
|
451
471
|
|
@@ -462,22 +482,37 @@ module Puma
|
|
462
482
|
when "t"
|
463
483
|
w.term unless w.term?
|
464
484
|
when "p"
|
465
|
-
|
466
|
-
|
485
|
+
status = result.sub(/^\d+/,'').chomp
|
486
|
+
w.ping!(status)
|
487
|
+
@events.fire(:ping!, w)
|
488
|
+
|
489
|
+
if in_phased_restart && workers_not_booted.positive? && w0 = worker_at(0)
|
490
|
+
w0.ping!(status)
|
491
|
+
@events.fire(:ping!, w0)
|
492
|
+
end
|
493
|
+
|
467
494
|
if !booted && @workers.none? {|worker| worker.last_status.empty?}
|
468
|
-
@
|
495
|
+
@events.fire_on_booted!
|
496
|
+
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
469
497
|
booted = true
|
470
498
|
end
|
499
|
+
when "i"
|
500
|
+
if @idle_workers[pid]
|
501
|
+
@idle_workers.delete pid
|
502
|
+
else
|
503
|
+
@idle_workers[pid] = true
|
504
|
+
end
|
471
505
|
end
|
472
506
|
else
|
473
507
|
log "! Out-of-sync worker list, no #{pid} worker"
|
474
508
|
end
|
475
509
|
end
|
510
|
+
|
476
511
|
if in_phased_restart && workers_not_booted.zero?
|
477
512
|
@events.fire_on_booted!
|
513
|
+
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
478
514
|
in_phased_restart = false
|
479
515
|
end
|
480
|
-
|
481
516
|
rescue Interrupt
|
482
517
|
@status = :stop
|
483
518
|
end
|
@@ -506,10 +541,28 @@ module Puma
|
|
506
541
|
# loops thru @workers, removing workers that exited, and calling
|
507
542
|
# `#term` if needed
|
508
543
|
def wait_workers
|
544
|
+
# Reap all children, known workers or otherwise.
|
545
|
+
# If puma has PID 1, as it's common in containerized environments,
|
546
|
+
# then it's responsible for reaping orphaned processes, so we must reap
|
547
|
+
# all our dead children, regardless of whether they are workers we spawned
|
548
|
+
# or some reattached processes.
|
549
|
+
reaped_children = {}
|
550
|
+
loop do
|
551
|
+
begin
|
552
|
+
pid, status = Process.wait2(-1, Process::WNOHANG)
|
553
|
+
break unless pid
|
554
|
+
reaped_children[pid] = status
|
555
|
+
rescue Errno::ECHILD
|
556
|
+
break
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
509
560
|
@workers.reject! do |w|
|
510
561
|
next false if w.pid.nil?
|
511
562
|
begin
|
512
|
-
|
563
|
+
# When `fork_worker` is enabled, some worker may not be direct children, but grand children.
|
564
|
+
# Because of this they won't be reaped by `Process.wait2(-1)`, so we need to check them individually)
|
565
|
+
if reaped_children.delete(w.pid) || (@options[:fork_worker] && Process.wait(w.pid, Process::WNOHANG))
|
513
566
|
true
|
514
567
|
else
|
515
568
|
w.term if w.term?
|
@@ -526,6 +579,11 @@ module Puma
|
|
526
579
|
end
|
527
580
|
end
|
528
581
|
end
|
582
|
+
|
583
|
+
# Log unknown children
|
584
|
+
reaped_children.each do |pid, status|
|
585
|
+
log "! reaped unknown child process pid=#{pid} status=#{status}"
|
586
|
+
end
|
529
587
|
end
|
530
588
|
|
531
589
|
# @version 5.0.0
|
@@ -533,14 +591,18 @@ module Puma
|
|
533
591
|
@workers.each do |w|
|
534
592
|
if !w.term? && w.ping_timeout <= Time.now
|
535
593
|
details = if w.booted?
|
536
|
-
"(
|
594
|
+
"(Worker #{w.index} failed to check in within #{@options[:worker_timeout]} seconds)"
|
537
595
|
else
|
538
|
-
"(
|
596
|
+
"(Worker #{w.index} failed to boot within #{@options[:worker_boot_timeout]} seconds)"
|
539
597
|
end
|
540
598
|
log "! Terminating timed out worker #{details}: #{w.pid}"
|
541
599
|
w.kill
|
542
600
|
end
|
543
601
|
end
|
544
602
|
end
|
603
|
+
|
604
|
+
def idle_timed_out_worker_pids
|
605
|
+
@idle_workers.keys
|
606
|
+
end
|
545
607
|
end
|
546
608
|
end
|
data/lib/puma/commonlogger.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Puma
|
4
4
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
5
5
|
# logs a line in the
|
6
|
-
# {Apache common log format}[https://httpd.apache.org/docs/
|
6
|
+
# {Apache common log format}[https://httpd.apache.org/docs/2.4/logs.html#common]
|
7
7
|
# to the +logger+.
|
8
8
|
#
|
9
9
|
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
@@ -16,7 +16,7 @@ module Puma
|
|
16
16
|
# (which is called without arguments in order to make the error appear for
|
17
17
|
# sure)
|
18
18
|
class CommonLogger
|
19
|
-
# Common Log Format: https://httpd.apache.org/docs/
|
19
|
+
# Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
|
20
20
|
#
|
21
21
|
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
22
22
|
#
|
@@ -25,10 +25,17 @@ module Puma
|
|
25
25
|
|
26
26
|
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
|
29
|
+
|
30
|
+
CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
|
31
|
+
# Util::HeaderHash allows mixed
|
32
|
+
HTTP_VERSION = Const::HTTP_VERSION
|
33
|
+
HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
|
34
|
+
PATH_INFO = Const::PATH_INFO
|
35
|
+
QUERY_STRING = Const::QUERY_STRING
|
36
|
+
REMOTE_ADDR = Const::REMOTE_ADDR
|
37
|
+
REMOTE_USER = 'REMOTE_USER'
|
38
|
+
REQUEST_METHOD = Const::REQUEST_METHOD
|
32
39
|
|
33
40
|
def initialize(app, logger=nil)
|
34
41
|
@app = app
|
@@ -57,13 +64,13 @@ module Puma
|
|
57
64
|
now = Time.now
|
58
65
|
|
59
66
|
msg = HIJACK_FORMAT % [
|
60
|
-
env[
|
61
|
-
env[
|
62
|
-
now.strftime(
|
67
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
68
|
+
env[REMOTE_USER] || "-",
|
69
|
+
now.strftime(LOG_TIME_FORMAT),
|
63
70
|
env[REQUEST_METHOD],
|
64
71
|
env[PATH_INFO],
|
65
72
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
66
|
-
env[
|
73
|
+
env[HTTP_VERSION],
|
67
74
|
now - began_at ]
|
68
75
|
|
69
76
|
write(msg)
|
@@ -74,13 +81,13 @@ module Puma
|
|
74
81
|
length = extract_content_length(header)
|
75
82
|
|
76
83
|
msg = FORMAT % [
|
77
|
-
env[
|
78
|
-
env[
|
79
|
-
now.strftime(
|
84
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
85
|
+
env[REMOTE_USER] || "-",
|
86
|
+
now.strftime(LOG_TIME_FORMAT),
|
80
87
|
env[REQUEST_METHOD],
|
81
88
|
env[PATH_INFO],
|
82
89
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
83
|
-
env[
|
90
|
+
env[HTTP_VERSION],
|
84
91
|
status.to_s[0..3],
|
85
92
|
length,
|
86
93
|
now - began_at ]
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,21 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require_relative 'rack/builder'
|
4
|
+
require_relative 'plugin'
|
5
|
+
require_relative 'const'
|
6
|
+
require_relative 'dsl'
|
6
7
|
|
7
8
|
module Puma
|
8
|
-
|
9
|
-
module ConfigDefault
|
10
|
-
DefaultRackup = "config.ru"
|
11
|
-
|
12
|
-
DefaultTCPHost = "0.0.0.0"
|
13
|
-
DefaultTCPPort = 9292
|
14
|
-
DefaultWorkerCheckInterval = 5
|
15
|
-
DefaultWorkerTimeout = 60
|
16
|
-
DefaultWorkerShutdownTimeout = 30
|
17
|
-
end
|
18
|
-
|
19
9
|
# A class used for storing "leveled" configuration options.
|
20
10
|
#
|
21
11
|
# In this class any "user" specified options take precedence over any
|
@@ -136,7 +126,52 @@ module Puma
|
|
136
126
|
# is done because an environment variable may have been modified while loading
|
137
127
|
# configuration files.
|
138
128
|
class Configuration
|
139
|
-
|
129
|
+
DEFAULTS = {
|
130
|
+
auto_trim_time: 30,
|
131
|
+
binds: ['tcp://0.0.0.0:9292'.freeze],
|
132
|
+
clean_thread_locals: false,
|
133
|
+
debug: false,
|
134
|
+
early_hints: nil,
|
135
|
+
environment: 'development'.freeze,
|
136
|
+
# Number of seconds to wait until we get the first data for the request.
|
137
|
+
first_data_timeout: 30,
|
138
|
+
# Number of seconds to wait until the next request before shutting down.
|
139
|
+
idle_timeout: nil,
|
140
|
+
io_selector_backend: :auto,
|
141
|
+
log_requests: false,
|
142
|
+
logger: STDOUT,
|
143
|
+
# How many requests to attempt inline before sending a client back to
|
144
|
+
# the reactor to be subject to normal ordering. The idea here is that
|
145
|
+
# we amortize the cost of going back to the reactor for a well behaved
|
146
|
+
# but very "greedy" client across 10 requests. This prevents a not
|
147
|
+
# well behaved client from monopolizing the thread forever.
|
148
|
+
max_fast_inline: 10,
|
149
|
+
max_threads: Puma.mri? ? 5 : 16,
|
150
|
+
min_threads: 0,
|
151
|
+
mode: :http,
|
152
|
+
mutate_stdout_and_stderr_to_sync_on_write: true,
|
153
|
+
out_of_band: [],
|
154
|
+
# Number of seconds for another request within a persistent session.
|
155
|
+
persistent_timeout: 20,
|
156
|
+
queue_requests: true,
|
157
|
+
rackup: 'config.ru'.freeze,
|
158
|
+
raise_exception_on_sigterm: true,
|
159
|
+
reaping_time: 1,
|
160
|
+
remote_address: :socket,
|
161
|
+
silence_single_worker_warning: false,
|
162
|
+
silence_fork_callback_warning: false,
|
163
|
+
tag: File.basename(Dir.getwd),
|
164
|
+
tcp_host: '0.0.0.0'.freeze,
|
165
|
+
tcp_port: 9292,
|
166
|
+
wait_for_less_busy_worker: 0.005,
|
167
|
+
worker_boot_timeout: 60,
|
168
|
+
worker_check_interval: 5,
|
169
|
+
worker_culling_strategy: :youngest,
|
170
|
+
worker_shutdown_timeout: 30,
|
171
|
+
worker_timeout: 60,
|
172
|
+
workers: 0,
|
173
|
+
http_content_length_limit: nil
|
174
|
+
}
|
140
175
|
|
141
176
|
def initialize(user_options={}, default_options = {}, &block)
|
142
177
|
default_options = self.puma_default_options.merge(default_options)
|
@@ -181,37 +216,22 @@ module Puma
|
|
181
216
|
self
|
182
217
|
end
|
183
218
|
|
184
|
-
|
185
|
-
|
186
|
-
|
219
|
+
def puma_default_options
|
220
|
+
defaults = DEFAULTS.dup
|
221
|
+
puma_options_from_env.each { |k,v| defaults[k] = v if v }
|
222
|
+
defaults
|
187
223
|
end
|
188
224
|
|
189
|
-
def
|
225
|
+
def puma_options_from_env
|
226
|
+
min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
|
227
|
+
max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
|
228
|
+
workers = ENV['WEB_CONCURRENCY']
|
229
|
+
|
190
230
|
{
|
191
|
-
:
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:
|
195
|
-
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
196
|
-
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
197
|
-
:silence_single_worker_warning => false,
|
198
|
-
:mode => :http,
|
199
|
-
:worker_check_interval => DefaultWorkerCheckInterval,
|
200
|
-
:worker_timeout => DefaultWorkerTimeout,
|
201
|
-
:worker_boot_timeout => DefaultWorkerTimeout,
|
202
|
-
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
203
|
-
:worker_culling_strategy => :youngest,
|
204
|
-
:remote_address => :socket,
|
205
|
-
:tag => method(:infer_tag),
|
206
|
-
:environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
|
207
|
-
:rackup => DefaultRackup,
|
208
|
-
:logger => STDOUT,
|
209
|
-
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
210
|
-
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
211
|
-
:raise_exception_on_sigterm => true,
|
212
|
-
:max_fast_inline => Const::MAX_FAST_INLINE,
|
213
|
-
:io_selector_backend => :auto,
|
214
|
-
:mutate_stdout_and_stderr_to_sync_on_write => true,
|
231
|
+
min_threads: min && Integer(min),
|
232
|
+
max_threads: max && Integer(max),
|
233
|
+
workers: workers && Integer(workers),
|
234
|
+
environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
|
215
235
|
}
|
216
236
|
end
|
217
237
|
|
@@ -227,7 +247,7 @@ module Puma
|
|
227
247
|
return [] if files == ['-']
|
228
248
|
return files if files.any?
|
229
249
|
|
230
|
-
first_default_file = %W(config/puma/#{
|
250
|
+
first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
|
231
251
|
File.exist?(f)
|
232
252
|
end
|
233
253
|
|
@@ -270,7 +290,7 @@ module Puma
|
|
270
290
|
found = options[:app] || load_rackup
|
271
291
|
|
272
292
|
if @options[:log_requests]
|
273
|
-
|
293
|
+
require_relative 'commonlogger'
|
274
294
|
logger = @options[:logger]
|
275
295
|
found = CommonLogger.new(found, logger)
|
276
296
|
end
|
@@ -283,21 +303,25 @@ module Puma
|
|
283
303
|
@options[:environment]
|
284
304
|
end
|
285
305
|
|
286
|
-
def environment_str
|
287
|
-
environment.respond_to?(:call) ? environment.call : environment
|
288
|
-
end
|
289
|
-
|
290
306
|
def load_plugin(name)
|
291
307
|
@plugins.create name
|
292
308
|
end
|
293
309
|
|
294
|
-
|
310
|
+
# @param key [:Symbol] hook to run
|
311
|
+
# @param arg [Launcher, Int] `:on_restart` passes Launcher
|
312
|
+
#
|
313
|
+
def run_hooks(key, arg, log_writer, hook_data = nil)
|
295
314
|
@options.all_of(key).each do |b|
|
296
315
|
begin
|
297
|
-
b
|
316
|
+
if Array === b
|
317
|
+
hook_data[b[1]] ||= Hash.new
|
318
|
+
b[0].call arg, hook_data[b[1]]
|
319
|
+
else
|
320
|
+
b.call arg
|
321
|
+
end
|
298
322
|
rescue => e
|
299
|
-
|
300
|
-
|
323
|
+
log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
324
|
+
log_writer.debug e.backtrace.join("\n")
|
301
325
|
end
|
302
326
|
end
|
303
327
|
end
|
@@ -315,10 +339,6 @@ module Puma
|
|
315
339
|
|
316
340
|
private
|
317
341
|
|
318
|
-
def infer_tag
|
319
|
-
File.basename(Dir.getwd)
|
320
|
-
end
|
321
|
-
|
322
342
|
# Load and use the normal Rack builder if we can, otherwise
|
323
343
|
# fallback to our minimal version.
|
324
344
|
def rack_builder
|
@@ -367,5 +387,3 @@ module Puma
|
|
367
387
|
end
|
368
388
|
end
|
369
389
|
end
|
370
|
-
|
371
|
-
require 'puma/dsl'
|