puma 5.2.2 → 6.3.0
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 +483 -4
- data/README.md +101 -20
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +50 -16
- data/docs/compile_options.md +38 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +1 -3
- data/docs/jungle/rc.d/README.md +1 -1
- data/docs/kubernetes.md +1 -1
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +7 -7
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +65 -69
- 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 +44 -13
- data/ext/puma_http11/http11_parser.c +24 -11
- data/ext/puma_http11/http11_parser.h +2 -2
- 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 +3 -3
- data/ext/puma_http11/mini_ssl.c +150 -23
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +10 -7
- data/lib/puma/binder.rb +112 -62
- data/lib/puma/cli.rb +24 -20
- data/lib/puma/client.rb +162 -36
- data/lib/puma/cluster/worker.rb +31 -27
- data/lib/puma/cluster/worker_handle.rb +12 -1
- data/lib/puma/cluster.rb +102 -61
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +78 -54
- data/lib/puma/const.rb +135 -97
- data/lib/puma/control_cli.rb +25 -20
- data/lib/puma/detect.rb +12 -2
- data/lib/puma/dsl.rb +308 -58
- data/lib/puma/error_logger.rb +20 -11
- 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.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +114 -173
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +30 -16
- data/lib/puma/minissl.rb +132 -38
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/rack/builder.rb +7 -7
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +373 -153
- data/lib/puma/runner.rb +74 -28
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +127 -136
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/thread_pool.rb +33 -26
- data/lib/puma/util.rb +20 -15
- data/lib/puma.rb +28 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +1 -1
- metadata +15 -10
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/dsl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'const'
|
4
|
+
require_relative 'util'
|
4
5
|
|
5
6
|
module Puma
|
6
7
|
# The methods that are available for use inside the configuration file.
|
@@ -31,8 +32,24 @@ module Puma
|
|
31
32
|
# You can also find many examples being used by the test suite in
|
32
33
|
# +test/config+.
|
33
34
|
#
|
35
|
+
# Puma v6 adds the option to specify a key name (String or Symbol) to the
|
36
|
+
# hooks that run inside the forked workers. All the hooks run inside the
|
37
|
+
# {Puma::Cluster::Worker#run} method.
|
38
|
+
#
|
39
|
+
# Previously, the worker index and the LogWriter instance were passed to the
|
40
|
+
# hook blocks/procs. If a key name is specified, a hash is passed as the last
|
41
|
+
# parameter. This allows storage of data, typically objects that are created
|
42
|
+
# before the worker that need to be passed to the hook when the worker is shutdown.
|
43
|
+
#
|
44
|
+
# The following hooks have been updated:
|
45
|
+
#
|
46
|
+
# | DSL Method | Options Key | Fork Block Location |
|
47
|
+
# | on_worker_boot | :before_worker_boot | inside, before |
|
48
|
+
# | on_worker_shutdown | :before_worker_shutdown | inside, after |
|
49
|
+
# | on_refork | :before_refork | inside |
|
50
|
+
#
|
34
51
|
class DSL
|
35
|
-
|
52
|
+
ON_WORKER_KEY = [String, Symbol].freeze
|
36
53
|
|
37
54
|
# convenience method so logic can be used in CI
|
38
55
|
# @see ssl_bind
|
@@ -46,25 +63,60 @@ module Puma
|
|
46
63
|
else ''
|
47
64
|
end
|
48
65
|
|
49
|
-
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
66
|
+
ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
|
67
|
+
|
68
|
+
low_latency_str = opts.key?(:low_latency) ? "&low_latency=#{opts[:low_latency]}" : ''
|
69
|
+
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
|
50
70
|
|
51
71
|
if defined?(JRUBY_VERSION)
|
52
|
-
|
53
|
-
|
72
|
+
cipher_suites = opts[:ssl_cipher_list] ? "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil # old name
|
73
|
+
cipher_suites = "#{cipher_suites}&cipher_suites=#{opts[:cipher_suites]}" if opts[:cipher_suites]
|
74
|
+
protocols = opts[:protocols] ? "&protocols=#{opts[:protocols]}" : nil
|
54
75
|
|
55
76
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
77
|
+
keystore_additions = "#{keystore_additions}&keystore-type=#{opts[:keystore_type]}" if opts[:keystore_type]
|
78
|
+
if opts[:truststore]
|
79
|
+
truststore_additions = "&truststore=#{opts[:truststore]}"
|
80
|
+
truststore_additions = "#{truststore_additions}&truststore-pass=#{opts[:truststore_pass]}" if opts[:truststore_pass]
|
81
|
+
truststore_additions = "#{truststore_additions}&truststore-type=#{opts[:truststore_type]}" if opts[:truststore_type]
|
82
|
+
end
|
56
83
|
|
57
|
-
"ssl://#{host}:#{port}?#{keystore_additions}#{
|
58
|
-
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
84
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{truststore_additions}#{cipher_suites}#{protocols}" \
|
85
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
|
59
86
|
else
|
60
|
-
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
87
|
+
ssl_cipher_filter = opts[:ssl_cipher_filter] ? "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
88
|
+
v_flags = (ary = opts[:verification_flags]) ? "&verification_flags=#{Array(ary).join ','}" : nil
|
89
|
+
|
90
|
+
cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(cert)}" : nil
|
91
|
+
key_flags = (key = opts[:key]) ? "&key=#{Puma::Util.escape(key)}" : nil
|
92
|
+
password_flags = (password_command = opts[:key_password_command]) ? "&key_password_command=#{Puma::Util.escape(password_command)}" : nil
|
93
|
+
|
94
|
+
reuse_flag =
|
95
|
+
if (reuse = opts[:reuse])
|
96
|
+
if reuse == true
|
97
|
+
'&reuse=dflt'
|
98
|
+
elsif reuse.is_a?(Hash) && (reuse.key?(:size) || reuse.key?(:timeout))
|
99
|
+
val = +''
|
100
|
+
if (size = reuse[:size]) && Integer === size
|
101
|
+
val << size.to_s
|
102
|
+
end
|
103
|
+
if (timeout = reuse[:timeout]) && Integer === timeout
|
104
|
+
val << ",#{timeout}"
|
105
|
+
end
|
106
|
+
if val.empty?
|
107
|
+
nil
|
108
|
+
else
|
109
|
+
"&reuse=#{val}"
|
110
|
+
end
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
else
|
115
|
+
nil
|
116
|
+
end
|
65
117
|
|
66
|
-
"ssl://#{host}:#{port}
|
67
|
-
"#{
|
118
|
+
"ssl://#{host}:#{port}?#{cert_flags}#{key_flags}#{password_flags}#{ssl_cipher_filter}" \
|
119
|
+
"#{reuse_flag}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}#{low_latency_str}"
|
68
120
|
end
|
69
121
|
end
|
70
122
|
|
@@ -100,7 +152,7 @@ module Puma
|
|
100
152
|
end
|
101
153
|
|
102
154
|
def default_host
|
103
|
-
@options[:default_host] || Configuration::
|
155
|
+
@options[:default_host] || Configuration::DEFAULTS[:tcp_host]
|
104
156
|
end
|
105
157
|
|
106
158
|
def inject(&blk)
|
@@ -191,7 +243,7 @@ module Puma
|
|
191
243
|
end
|
192
244
|
|
193
245
|
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
194
|
-
# accepted protocols. Multiple urls can be bound to, calling
|
246
|
+
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
|
195
247
|
# not overwrite previous bindings.
|
196
248
|
#
|
197
249
|
# The default is "tcp://0.0.0.0:9292".
|
@@ -200,8 +252,9 @@ module Puma
|
|
200
252
|
#
|
201
253
|
# * Set the socket backlog depth with +backlog+, default is 1024.
|
202
254
|
# * Set up an SSL certificate with +key+ & +cert+.
|
255
|
+
# * Set up an SSL certificate for mTLS with +key+, +cert+, +ca+ and +verify_mode+.
|
203
256
|
# * Set whether to optimize for low latency instead of throughput with
|
204
|
-
# +low_latency+, default is to optimize for low latency. This is done
|
257
|
+
# +low_latency+, default is to not optimize for low latency. This is done
|
205
258
|
# via +Socket::TCP_NODELAY+.
|
206
259
|
# * Set socket permissions with +umask+.
|
207
260
|
#
|
@@ -209,6 +262,8 @@ module Puma
|
|
209
262
|
# bind 'unix:///var/run/puma.sock?backlog=512'
|
210
263
|
# @example SSL cert
|
211
264
|
# bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
|
265
|
+
# @example SSL cert for mutual TLS (mTLS)
|
266
|
+
# bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem&ca=ca.pem&verify_mode=force_peer'
|
212
267
|
# @example Disable optimization for low latency
|
213
268
|
# bind 'tcp://0.0.0.0:9292?low_latency=false'
|
214
269
|
# @example Socket permissions
|
@@ -365,6 +420,11 @@ module Puma
|
|
365
420
|
@options[:log_requests] = which
|
366
421
|
end
|
367
422
|
|
423
|
+
# Pass in a custom logging class instance
|
424
|
+
def custom_logger(custom_logger)
|
425
|
+
@options[:custom_logger] = custom_logger
|
426
|
+
end
|
427
|
+
|
368
428
|
# Show debugging info
|
369
429
|
#
|
370
430
|
def debug
|
@@ -381,6 +441,13 @@ module Puma
|
|
381
441
|
@options[:rackup] ||= path.to_s
|
382
442
|
end
|
383
443
|
|
444
|
+
# Allows setting `env['rack.url_scheme']`.
|
445
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
446
|
+
# Normal values are 'http' or 'https'.
|
447
|
+
def rack_url_scheme(scheme=nil)
|
448
|
+
@options[:rack_url_scheme] = scheme
|
449
|
+
end
|
450
|
+
|
384
451
|
def early_hints(answer=true)
|
385
452
|
@options[:early_hints] = answer
|
386
453
|
end
|
@@ -429,8 +496,19 @@ module Puma
|
|
429
496
|
@options[:max_threads] = max
|
430
497
|
end
|
431
498
|
|
432
|
-
# Instead of
|
433
|
-
#
|
499
|
+
# Instead of using +bind+ and manually constructing a URI like:
|
500
|
+
#
|
501
|
+
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
|
502
|
+
#
|
503
|
+
# you can use the this method.
|
504
|
+
#
|
505
|
+
# When binding on localhost you don't need to specify +cert+ and +key+,
|
506
|
+
# Puma will assume you are using the +localhost+ gem and try to load the
|
507
|
+
# appropriate files.
|
508
|
+
#
|
509
|
+
# When using the options hash parameter, the `reuse:` value is either
|
510
|
+
# `true`, which sets reuse 'on' with default values, or a hash, with `:size`
|
511
|
+
# and/or `:timeout` keys, each with integer values.
|
434
512
|
#
|
435
513
|
# @example
|
436
514
|
# ssl_bind '127.0.0.1', '9292', {
|
@@ -439,15 +517,28 @@ module Puma
|
|
439
517
|
# ssl_cipher_filter: cipher_filter, # optional
|
440
518
|
# verify_mode: verify_mode, # default 'none'
|
441
519
|
# verification_flags: flags, # optional, not supported by JRuby
|
520
|
+
# reuse: true # optional
|
442
521
|
# }
|
443
|
-
#
|
522
|
+
#
|
523
|
+
# @example Using self-signed certificate with the +localhost+ gem:
|
524
|
+
# ssl_bind '127.0.0.1', '9292'
|
525
|
+
#
|
526
|
+
# @example Alternatively, you can provide +cert_pem+ and +key_pem+:
|
527
|
+
# ssl_bind '127.0.0.1', '9292', {
|
528
|
+
# cert_pem: File.read(path_to_cert),
|
529
|
+
# key_pem: File.read(path_to_key),
|
530
|
+
# reuse: {size: 2_000, timeout: 20} # optional
|
531
|
+
# }
|
532
|
+
#
|
533
|
+
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
|
444
534
|
# ssl_bind '127.0.0.1', '9292', {
|
445
535
|
# keystore: path_to_keystore,
|
446
536
|
# keystore_pass: password,
|
447
537
|
# ssl_cipher_list: cipher_list, # optional
|
448
538
|
# verify_mode: verify_mode # default 'none'
|
449
539
|
# }
|
450
|
-
def ssl_bind(host, port, opts)
|
540
|
+
def ssl_bind(host, port, opts = {})
|
541
|
+
add_pem_values_to_options_store(opts)
|
451
542
|
bind self.class.ssl_bind_str(host, port, opts)
|
452
543
|
end
|
453
544
|
|
@@ -482,6 +573,29 @@ module Puma
|
|
482
573
|
@options[:workers] = count.to_i
|
483
574
|
end
|
484
575
|
|
576
|
+
# Disable warning message when running in cluster mode with a single worker.
|
577
|
+
#
|
578
|
+
# Cluster mode has some overhead of running an additional 'control' process
|
579
|
+
# in order to manage the cluster. If only running a single worker it is
|
580
|
+
# likely not worth paying that overhead vs running in single mode with
|
581
|
+
# additional threads instead.
|
582
|
+
#
|
583
|
+
# There are some scenarios where running cluster mode with a single worker
|
584
|
+
# may still be warranted and valid under certain deployment scenarios, see
|
585
|
+
# https://github.com/puma/puma/issues/2534
|
586
|
+
#
|
587
|
+
# Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
|
588
|
+
#
|
589
|
+
# @note Cluster mode only.
|
590
|
+
def silence_single_worker_warning
|
591
|
+
@options[:silence_single_worker_warning] = true
|
592
|
+
end
|
593
|
+
|
594
|
+
# Disable warning message when running single mode with callback hook defined.
|
595
|
+
def silence_fork_callback_warning
|
596
|
+
@options[:silence_fork_callback_warning] = true
|
597
|
+
end
|
598
|
+
|
485
599
|
# Code to run immediately before master process
|
486
600
|
# forks workers (once on boot). These hooks can block if necessary
|
487
601
|
# to wait for background operations unknown to Puma to finish before
|
@@ -497,6 +611,8 @@ module Puma
|
|
497
611
|
# puts "Starting workers..."
|
498
612
|
# end
|
499
613
|
def before_fork(&block)
|
614
|
+
warn_if_in_single_mode('before_fork')
|
615
|
+
|
500
616
|
@options[:before_fork] ||= []
|
501
617
|
@options[:before_fork] << block
|
502
618
|
end
|
@@ -511,9 +627,10 @@ module Puma
|
|
511
627
|
# on_worker_boot do
|
512
628
|
# puts 'Before worker boot...'
|
513
629
|
# end
|
514
|
-
def on_worker_boot(&block)
|
515
|
-
|
516
|
-
|
630
|
+
def on_worker_boot(key = nil, &block)
|
631
|
+
warn_if_in_single_mode('on_worker_boot')
|
632
|
+
|
633
|
+
process_hook :before_worker_boot, key, block, 'on_worker_boot'
|
517
634
|
end
|
518
635
|
|
519
636
|
# Code to run immediately before a worker shuts
|
@@ -528,9 +645,10 @@ module Puma
|
|
528
645
|
# on_worker_shutdown do
|
529
646
|
# puts 'On worker shutdown...'
|
530
647
|
# end
|
531
|
-
def on_worker_shutdown(&block)
|
532
|
-
|
533
|
-
|
648
|
+
def on_worker_shutdown(key = nil, &block)
|
649
|
+
warn_if_in_single_mode('on_worker_shutdown')
|
650
|
+
|
651
|
+
process_hook :before_worker_shutdown, key, block, 'on_worker_shutdown'
|
534
652
|
end
|
535
653
|
|
536
654
|
# Code to run in the master right before a worker is started. The worker's
|
@@ -544,8 +662,9 @@ module Puma
|
|
544
662
|
# puts 'Before worker fork...'
|
545
663
|
# end
|
546
664
|
def on_worker_fork(&block)
|
547
|
-
|
548
|
-
|
665
|
+
warn_if_in_single_mode('on_worker_fork')
|
666
|
+
|
667
|
+
process_hook :before_worker_fork, nil, block, 'on_worker_fork'
|
549
668
|
end
|
550
669
|
|
551
670
|
# Code to run in the master after a worker has been started. The worker's
|
@@ -559,12 +678,23 @@ module Puma
|
|
559
678
|
# puts 'After worker fork...'
|
560
679
|
# end
|
561
680
|
def after_worker_fork(&block)
|
562
|
-
|
563
|
-
|
681
|
+
warn_if_in_single_mode('after_worker_fork')
|
682
|
+
|
683
|
+
process_hook :after_worker_fork, nil, block, 'after_worker_fork'
|
564
684
|
end
|
565
685
|
|
566
686
|
alias_method :after_worker_boot, :after_worker_fork
|
567
687
|
|
688
|
+
# Code to run after puma is booted (works for both: single and clustered)
|
689
|
+
#
|
690
|
+
# @example
|
691
|
+
# on_booted do
|
692
|
+
# puts 'After booting...'
|
693
|
+
# end
|
694
|
+
def on_booted(&block)
|
695
|
+
@config.options[:events].on_booted(&block)
|
696
|
+
end
|
697
|
+
|
568
698
|
# When `fork_worker` is enabled, code to run in Worker 0
|
569
699
|
# before all other workers are re-forked from this process,
|
570
700
|
# after the server has temporarily stopped serving requests
|
@@ -583,9 +713,8 @@ module Puma
|
|
583
713
|
# end
|
584
714
|
# @version 5.0.0
|
585
715
|
#
|
586
|
-
def on_refork(&block)
|
587
|
-
|
588
|
-
@options[:before_refork] << block
|
716
|
+
def on_refork(key = nil, &block)
|
717
|
+
process_hook :before_refork, key, block, 'on_refork'
|
589
718
|
end
|
590
719
|
|
591
720
|
# Code to run out-of-band when the worker is idle.
|
@@ -598,8 +727,7 @@ module Puma
|
|
598
727
|
#
|
599
728
|
# This can be called multiple times to add several hooks.
|
600
729
|
def out_of_band(&block)
|
601
|
-
|
602
|
-
@options[:out_of_band] << block
|
730
|
+
process_hook :out_of_band, nil, block, 'out_of_band'
|
603
731
|
end
|
604
732
|
|
605
733
|
# The directory to operate out of.
|
@@ -702,6 +830,19 @@ module Puma
|
|
702
830
|
@options[:tag] = string.to_s
|
703
831
|
end
|
704
832
|
|
833
|
+
# Change the default interval for checking workers.
|
834
|
+
#
|
835
|
+
# The default value is 5 seconds.
|
836
|
+
#
|
837
|
+
# @note Cluster mode only.
|
838
|
+
# @example
|
839
|
+
# worker_check_interval 5
|
840
|
+
# @see Puma::Cluster#check_workers
|
841
|
+
#
|
842
|
+
def worker_check_interval(interval)
|
843
|
+
@options[:worker_check_interval] = Integer(interval)
|
844
|
+
end
|
845
|
+
|
705
846
|
# Verifies that all workers have checked in to the master process within
|
706
847
|
# the given timeout. If not the worker process will be restarted. This is
|
707
848
|
# not a request timeout, it is to protect against a hung or dead process.
|
@@ -716,7 +857,7 @@ module Puma
|
|
716
857
|
#
|
717
858
|
def worker_timeout(timeout)
|
718
859
|
timeout = Integer(timeout)
|
719
|
-
min =
|
860
|
+
min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
|
720
861
|
|
721
862
|
if timeout <= min
|
722
863
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
@@ -748,6 +889,30 @@ module Puma
|
|
748
889
|
@options[:worker_shutdown_timeout] = Integer(timeout)
|
749
890
|
end
|
750
891
|
|
892
|
+
# Set the strategy for worker culling.
|
893
|
+
#
|
894
|
+
# There are two possible values:
|
895
|
+
#
|
896
|
+
# 1. **:youngest** - the youngest workers (i.e. the workers that were
|
897
|
+
# the most recently started) will be culled.
|
898
|
+
# 2. **:oldest** - the oldest workers (i.e. the workers that were started
|
899
|
+
# the longest time ago) will be culled.
|
900
|
+
#
|
901
|
+
# @note Cluster mode only.
|
902
|
+
# @example
|
903
|
+
# worker_culling_strategy :oldest
|
904
|
+
# @see Puma::Cluster#cull_workers
|
905
|
+
#
|
906
|
+
def worker_culling_strategy(strategy)
|
907
|
+
stategy = strategy.to_sym
|
908
|
+
|
909
|
+
if ![:youngest, :oldest].include?(strategy)
|
910
|
+
raise "Invalid value for worker_culling_strategy - #{stategy}"
|
911
|
+
end
|
912
|
+
|
913
|
+
@options[:worker_culling_strategy] = strategy
|
914
|
+
end
|
915
|
+
|
751
916
|
# When set to true (the default), workers accept all requests
|
752
917
|
# and queue them before passing them to the handlers.
|
753
918
|
# When set to false, each worker process accepts exactly as
|
@@ -793,17 +958,23 @@ module Puma
|
|
793
958
|
# a kernel syscall is required which for very fast rack handlers
|
794
959
|
# slows down the handling significantly.
|
795
960
|
#
|
796
|
-
# There are
|
961
|
+
# There are 5 possible values:
|
797
962
|
#
|
798
963
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
799
|
-
# syscall. This is the normal behavior.
|
964
|
+
# syscall. This is the normal behavior. If this fails for any reason (e.g.,
|
965
|
+
# if the peer disconnects between the connection being accepted and the getpeername
|
966
|
+
# system call), Puma will return "0.0.0.0"
|
800
967
|
# 2. **:localhost** - set the remote address to "127.0.0.1"
|
801
968
|
# 3. **header: <http_header>**- set the remote address to the value of the
|
802
969
|
# provided http header. For instance:
|
803
970
|
# `set_remote_address header: "X-Real-IP"`.
|
804
971
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
805
|
-
# headers such as X-Forwarded-For to be used as well.
|
806
|
-
#
|
972
|
+
# headers such as X-Forwarded-For to be used as well. If this header is absent,
|
973
|
+
# Puma will fall back to the behavior of :socket
|
974
|
+
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
975
|
+
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
976
|
+
# protocol attached to it, will fall back to :socket
|
977
|
+
# 5. **\<Any string\>** - this allows you to hardcode remote address to any value
|
807
978
|
# you wish. Because Puma never uses this field anyway, it's format is
|
808
979
|
# entirely in your hands.
|
809
980
|
#
|
@@ -821,6 +992,13 @@ module Puma
|
|
821
992
|
if hdr = val[:header]
|
822
993
|
@options[:remote_address] = :header
|
823
994
|
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
995
|
+
elsif protocol_version = val[:proxy_protocol]
|
996
|
+
@options[:remote_address] = :proxy_protocol
|
997
|
+
protocol_version = protocol_version.downcase.to_sym
|
998
|
+
unless [:v1].include?(protocol_version)
|
999
|
+
raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
|
1000
|
+
end
|
1001
|
+
@options[:remote_address_proxy_protocol] = protocol_version
|
824
1002
|
else
|
825
1003
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
826
1004
|
end
|
@@ -846,23 +1024,6 @@ module Puma
|
|
846
1024
|
@options[:fork_worker] = Integer(after_requests)
|
847
1025
|
end
|
848
1026
|
|
849
|
-
# When enabled, Puma will GC 4 times before forking workers.
|
850
|
-
# If available (Ruby 2.7+), we will also call GC.compact.
|
851
|
-
# Not recommended for non-MRI Rubies.
|
852
|
-
#
|
853
|
-
# Based on the work of Koichi Sasada and Aaron Patterson, this option may
|
854
|
-
# decrease memory utilization of preload-enabled cluster-mode Pumas. It will
|
855
|
-
# also increase time to boot and fork. See your logs for details on how much
|
856
|
-
# time this adds to your boot process. For most apps, it will be less than one
|
857
|
-
# second.
|
858
|
-
#
|
859
|
-
# @see Puma::Cluster#nakayoshi_gc
|
860
|
-
# @version 5.0.0
|
861
|
-
#
|
862
|
-
def nakayoshi_fork(enabled=true)
|
863
|
-
@options[:nakayoshi_fork] = enabled
|
864
|
-
end
|
865
|
-
|
866
1027
|
# The number of requests to attempt inline before sending a client back to
|
867
1028
|
# the reactor to be subject to normal ordering.
|
868
1029
|
#
|
@@ -892,5 +1053,94 @@ module Puma
|
|
892
1053
|
def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
|
893
1054
|
@options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
|
894
1055
|
end
|
1056
|
+
|
1057
|
+
# Specify how big the request payload should be, in bytes.
|
1058
|
+
# This limit is compared against Content-Length HTTP header.
|
1059
|
+
# If the payload size (CONTENT_LENGTH) is larger than http_content_length_limit,
|
1060
|
+
# HTTP 413 status code is returned.
|
1061
|
+
#
|
1062
|
+
# When no Content-Length http header is present, it is compared against the
|
1063
|
+
# size of the body of the request.
|
1064
|
+
#
|
1065
|
+
# The default value for http_content_length_limit is nil.
|
1066
|
+
def http_content_length_limit(limit)
|
1067
|
+
@options[:http_content_length_limit] = limit
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# Supported http methods, which will replace `Puma::Const::SUPPORTED_HTTP_METHODS`.
|
1071
|
+
# The value of `:any` will allows all methods, otherwise, the value must be
|
1072
|
+
# an array of strings. Note that methods are all uppercase.
|
1073
|
+
#
|
1074
|
+
# `Puma::Const::SUPPORTED_HTTP_METHODS` is conservative, if you want a
|
1075
|
+
# complete set of methods, the methods defined by the
|
1076
|
+
# [IANA Method Registry](https://www.iana.org/assignments/http-methods/http-methods.xhtml)
|
1077
|
+
# are pre-defined as the constant `Puma::Const::IANA_HTTP_METHODS`.
|
1078
|
+
#
|
1079
|
+
# @note If the `methods` value is `:any`, no method check with be performed,
|
1080
|
+
# similar to Puma v5 and earlier.
|
1081
|
+
#
|
1082
|
+
# @example Adds 'PROPFIND' to existing supported methods
|
1083
|
+
# supported_http_methods(Puma::Const::SUPPORTED_HTTP_METHODS + ['PROPFIND'])
|
1084
|
+
# @example Restricts methods to the array elements
|
1085
|
+
# supported_http_methods %w[HEAD GET POST PUT DELETE OPTIONS PROPFIND]
|
1086
|
+
# @example Restricts methods to the methods in the IANA Registry
|
1087
|
+
# supported_http_methods Puma::Const::IANA_HTTP_METHODS
|
1088
|
+
# @example Allows any method
|
1089
|
+
# supported_http_methods :any
|
1090
|
+
#
|
1091
|
+
def supported_http_methods(methods)
|
1092
|
+
if methods == :any
|
1093
|
+
@options[:supported_http_methods] = :any
|
1094
|
+
elsif Array === methods && methods == (ary = methods.grep(String).uniq) &&
|
1095
|
+
!ary.empty?
|
1096
|
+
@options[:supported_http_methods] = ary
|
1097
|
+
else
|
1098
|
+
raise "supported_http_methods must be ':any' or a unique array of strings"
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
private
|
1103
|
+
|
1104
|
+
# To avoid adding cert_pem and key_pem as URI params, we store them on the
|
1105
|
+
# options[:store] from where Puma binder knows how to find and extract them.
|
1106
|
+
def add_pem_values_to_options_store(opts)
|
1107
|
+
return if defined?(JRUBY_VERSION)
|
1108
|
+
|
1109
|
+
@options[:store] ||= []
|
1110
|
+
|
1111
|
+
# Store cert_pem and key_pem to options[:store] if present
|
1112
|
+
[:cert, :key].each do |v|
|
1113
|
+
opt_key = :"#{v}_pem"
|
1114
|
+
if opts[opt_key]
|
1115
|
+
index = @options[:store].length
|
1116
|
+
@options[:store] << opts[opt_key]
|
1117
|
+
opts[v] = "store:#{index}"
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def process_hook(options_key, key, block, meth)
|
1123
|
+
@options[options_key] ||= []
|
1124
|
+
if ON_WORKER_KEY.include? key.class
|
1125
|
+
@options[options_key] << [block, key.to_sym]
|
1126
|
+
elsif key.nil?
|
1127
|
+
@options[options_key] << block
|
1128
|
+
else
|
1129
|
+
raise "'#{meth}' key must be String or Symbol"
|
1130
|
+
end
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
def warn_if_in_single_mode(hook_name)
|
1134
|
+
return if @options[:silence_fork_callback_warning]
|
1135
|
+
|
1136
|
+
if (@options[:workers] || 0) == 0
|
1137
|
+
log_string =
|
1138
|
+
"Warning: You specified code to run in a `#{hook_name}` block, " \
|
1139
|
+
"but Puma is not configured to run in cluster mode (worker count > 0 ), " \
|
1140
|
+
"so your `#{hook_name}` block did not run"
|
1141
|
+
|
1142
|
+
LogWriter.stdio.log(log_string)
|
1143
|
+
end
|
1144
|
+
end
|
895
1145
|
end
|
896
1146
|
end
|
data/lib/puma/error_logger.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'const'
|
4
4
|
|
5
5
|
module Puma
|
6
6
|
# The implementation of a detailed error logging.
|
@@ -13,6 +13,8 @@ module Puma
|
|
13
13
|
|
14
14
|
REQUEST_FORMAT = %{"%s %s%s" - (%s)}
|
15
15
|
|
16
|
+
LOG_QUEUE = Queue.new
|
17
|
+
|
16
18
|
def initialize(ioerr)
|
17
19
|
@ioerr = ioerr
|
18
20
|
|
@@ -23,7 +25,7 @@ module Puma
|
|
23
25
|
new $stderr
|
24
26
|
end
|
25
27
|
|
26
|
-
# Print
|
28
|
+
# Print occurred error details.
|
27
29
|
# +options+ hash with additional options:
|
28
30
|
# - +error+ is an exception object
|
29
31
|
# - +req+ the http request
|
@@ -31,10 +33,10 @@ module Puma
|
|
31
33
|
# and before all remaining info.
|
32
34
|
#
|
33
35
|
def info(options={})
|
34
|
-
|
36
|
+
internal_write title(options)
|
35
37
|
end
|
36
38
|
|
37
|
-
# Print
|
39
|
+
# Print occurred error details only if
|
38
40
|
# environment variable PUMA_DEBUG is defined.
|
39
41
|
# +options+ hash with additional options:
|
40
42
|
# - +error+ is an exception object
|
@@ -53,7 +55,7 @@ module Puma
|
|
53
55
|
string_block << request_dump(req) if request_parsed?(req)
|
54
56
|
string_block << error.backtrace if error
|
55
57
|
|
56
|
-
|
58
|
+
internal_write string_block.join("\n")
|
57
59
|
end
|
58
60
|
|
59
61
|
def title(options={})
|
@@ -93,12 +95,19 @@ module Puma
|
|
93
95
|
req && req.env[REQUEST_METHOD]
|
94
96
|
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
def internal_write(str)
|
99
|
+
LOG_QUEUE << str
|
100
|
+
while (w_str = LOG_QUEUE.pop(true)) do
|
101
|
+
begin
|
102
|
+
@ioerr.is_a?(IO) and @ioerr.wait_writable(1)
|
103
|
+
@ioerr.write "#{w_str}\n"
|
104
|
+
@ioerr.flush unless @ioerr.sync
|
105
|
+
rescue Errno::EPIPE, Errno::EBADF, IOError, Errno::EINVAL
|
106
|
+
# 'Invalid argument' (Errno::EINVAL) may be raised by flush
|
107
|
+
end
|
108
|
+
end
|
109
|
+
rescue ThreadError
|
102
110
|
end
|
111
|
+
private :internal_write
|
103
112
|
end
|
104
113
|
end
|