puma 7.1.0-java → 8.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +116 -0
- data/README.md +18 -11
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/deployment.md +58 -23
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -0
- data/docs/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +3 -10
- data/docs/plugins.md +2 -2
- data/docs/signals.md +10 -10
- data/docs/stats.md +1 -1
- data/docs/systemd.md +3 -3
- data/ext/puma_http11/http11_parser.java.rl +51 -65
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +168 -104
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +71 -85
- data/ext/puma_http11/puma_http11.c +101 -109
- data/lib/puma/app/status.rb +10 -2
- data/lib/puma/cli.rb +1 -1
- data/lib/puma/client.rb +90 -66
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +10 -9
- data/lib/puma/cluster.rb +3 -4
- data/lib/puma/configuration.rb +85 -16
- data/lib/puma/const.rb +2 -2
- data/lib/puma/control_cli.rb +1 -1
- data/lib/puma/detect.rb +11 -0
- data/lib/puma/dsl.rb +90 -14
- data/lib/puma/launcher.rb +7 -7
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/reactor.rb +3 -12
- data/lib/puma/{request.rb → response.rb} +25 -194
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +72 -37
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +2 -2
- data/lib/puma/thread_pool.rb +129 -23
- data/lib/rack/handler/puma.rb +1 -1
- data/tools/Dockerfile +13 -5
- metadata +17 -7
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/configuration.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
3
6
|
require_relative 'plugin'
|
|
4
7
|
require_relative 'const'
|
|
5
8
|
require_relative 'dsl'
|
|
@@ -131,14 +134,16 @@ module Puma
|
|
|
131
134
|
|
|
132
135
|
DEFAULTS = {
|
|
133
136
|
auto_trim_time: 30,
|
|
134
|
-
binds: ['tcp://
|
|
135
|
-
fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
|
|
137
|
+
binds: ['tcp://[::]:9292'.freeze],
|
|
136
138
|
debug: false,
|
|
137
|
-
enable_keep_alives: true,
|
|
138
139
|
early_hints: nil,
|
|
140
|
+
enable_keep_alives: true,
|
|
139
141
|
environment: 'development'.freeze,
|
|
142
|
+
fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
|
|
140
143
|
# Number of seconds to wait until we get the first data for the request.
|
|
141
144
|
first_data_timeout: 30,
|
|
145
|
+
force_shutdown_after: -1,
|
|
146
|
+
http_content_length_limit: nil,
|
|
142
147
|
# Number of seconds to wait until the next request before shutting down.
|
|
143
148
|
idle_timeout: nil,
|
|
144
149
|
io_selector_backend: :auto,
|
|
@@ -147,6 +152,7 @@ module Puma
|
|
|
147
152
|
# Limits how many requests a keep alive connection can make.
|
|
148
153
|
# The connection will be closed after it reaches `max_keep_alive`
|
|
149
154
|
# requests.
|
|
155
|
+
max_io_threads: 0,
|
|
150
156
|
max_keep_alive: 999,
|
|
151
157
|
max_threads: Puma.mri? ? 5 : 16,
|
|
152
158
|
min_threads: 0,
|
|
@@ -161,10 +167,10 @@ module Puma
|
|
|
161
167
|
raise_exception_on_sigterm: true,
|
|
162
168
|
reaping_time: 1,
|
|
163
169
|
remote_address: :socket,
|
|
164
|
-
silence_single_worker_warning: false,
|
|
165
170
|
silence_fork_callback_warning: false,
|
|
171
|
+
silence_single_worker_warning: false,
|
|
166
172
|
tag: File.basename(Dir.getwd),
|
|
167
|
-
tcp_host: '
|
|
173
|
+
tcp_host: '::'.freeze,
|
|
168
174
|
tcp_port: 9292,
|
|
169
175
|
wait_for_less_busy_worker: 0.005,
|
|
170
176
|
worker_boot_timeout: 60,
|
|
@@ -173,11 +179,10 @@ module Puma
|
|
|
173
179
|
worker_shutdown_timeout: 30,
|
|
174
180
|
worker_timeout: 60,
|
|
175
181
|
workers: 0,
|
|
176
|
-
http_content_length_limit: nil
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
def initialize(user_options={}, default_options = {}, env = ENV, &block)
|
|
180
|
-
default_options = self.puma_default_options(env).merge(default_options)
|
|
185
|
+
default_options = self.puma_default_options(env).merge(events: Events.new).merge(default_options)
|
|
181
186
|
|
|
182
187
|
@_options = UserFileDefaultOptions.new(user_options, default_options)
|
|
183
188
|
@plugins = PluginLoader.new
|
|
@@ -197,7 +202,7 @@ module Puma
|
|
|
197
202
|
@clamped = false
|
|
198
203
|
end
|
|
199
204
|
|
|
200
|
-
attr_reader :plugins, :events, :hooks
|
|
205
|
+
attr_reader :plugins, :events, :hooks, :_options
|
|
201
206
|
|
|
202
207
|
def options
|
|
203
208
|
raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
|
|
@@ -230,6 +235,8 @@ module Puma
|
|
|
230
235
|
|
|
231
236
|
def puma_default_options(env = ENV)
|
|
232
237
|
defaults = DEFAULTS.dup
|
|
238
|
+
defaults[:tcp_host] = self.class.default_tcp_host
|
|
239
|
+
defaults[:binds] = [self.class.default_tcp_bind]
|
|
233
240
|
puma_options_from_env(env).each { |k,v| defaults[k] = v if v }
|
|
234
241
|
defaults
|
|
235
242
|
end
|
|
@@ -238,18 +245,14 @@ module Puma
|
|
|
238
245
|
min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
|
|
239
246
|
max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
|
|
240
247
|
persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
::Concurrent.available_processor_count
|
|
244
|
-
else
|
|
245
|
-
env['WEB_CONCURRENCY']
|
|
246
|
-
end
|
|
248
|
+
workers_env = env['WEB_CONCURRENCY']
|
|
249
|
+
workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
|
|
247
250
|
|
|
248
251
|
{
|
|
249
252
|
min_threads: min && min != "" && Integer(min),
|
|
250
253
|
max_threads: max && max != "" && Integer(max),
|
|
251
254
|
persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
|
|
252
|
-
workers: workers
|
|
255
|
+
workers: workers,
|
|
253
256
|
environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
|
|
254
257
|
}
|
|
255
258
|
end
|
|
@@ -281,8 +284,10 @@ module Puma
|
|
|
281
284
|
# This also calls load if it hasn't been called yet.
|
|
282
285
|
def clamp
|
|
283
286
|
load unless @loaded
|
|
287
|
+
run_mode_hooks
|
|
284
288
|
set_conditional_default_options
|
|
285
289
|
@_options.finalize_values
|
|
290
|
+
rewrite_unavailable_ipv6_binds!
|
|
286
291
|
@clamped = true
|
|
287
292
|
warn_hooks
|
|
288
293
|
options
|
|
@@ -361,6 +366,23 @@ module Puma
|
|
|
361
366
|
options.final_options
|
|
362
367
|
end
|
|
363
368
|
|
|
369
|
+
def self.default_tcp_host
|
|
370
|
+
ipv6_interface_available? ? Const::UNSPECIFIED_IPV6 : Const::UNSPECIFIED_IPV4
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def self.default_tcp_bind(port = DEFAULTS[:tcp_port])
|
|
374
|
+
URI::Generic.build(scheme: 'tcp', host: default_tcp_host, port: Integer(port)).to_s
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def self.ipv6_interface_available?
|
|
378
|
+
Socket.getifaddrs.any? do |ifaddr|
|
|
379
|
+
addr = ifaddr.addr
|
|
380
|
+
addr&.ipv6? && !addr&.ipv6_loopback?
|
|
381
|
+
end
|
|
382
|
+
rescue StandardError
|
|
383
|
+
false
|
|
384
|
+
end
|
|
385
|
+
|
|
364
386
|
def self.temp_path
|
|
365
387
|
require 'tmpdir'
|
|
366
388
|
|
|
@@ -376,16 +398,52 @@ module Puma
|
|
|
376
398
|
|
|
377
399
|
private
|
|
378
400
|
|
|
401
|
+
def rewrite_unavailable_ipv6_binds!
|
|
402
|
+
return if self.class.ipv6_interface_available?
|
|
403
|
+
|
|
404
|
+
tried_ipv6_bind = false
|
|
405
|
+
bind_schemes = ['tcp', 'ssl']
|
|
406
|
+
|
|
407
|
+
@_options[:binds] = Array(@_options[:binds]).map do |bind|
|
|
408
|
+
uri = URI.parse(bind)
|
|
409
|
+
next bind unless bind_schemes.include?(uri.scheme)
|
|
410
|
+
|
|
411
|
+
host = uri.host&.delete_prefix('[')&.delete_suffix(']')
|
|
412
|
+
next bind unless host&.include?(':')
|
|
413
|
+
|
|
414
|
+
tried_ipv6_bind = true
|
|
415
|
+
next bind unless host == Const::UNSPECIFIED_IPV6
|
|
416
|
+
|
|
417
|
+
uri.host = Const::UNSPECIFIED_IPV4
|
|
418
|
+
uri.to_s
|
|
419
|
+
rescue URI::InvalidURIError
|
|
420
|
+
bind
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
warn "WARNING: IPv6 bind requested but no non-loopback IPv6 interface was detected" if tried_ipv6_bind
|
|
424
|
+
end
|
|
425
|
+
|
|
379
426
|
def require_processor_counter
|
|
380
427
|
require 'concurrent/utility/processor_counter'
|
|
381
428
|
rescue LoadError
|
|
382
429
|
warn <<~MESSAGE
|
|
383
|
-
WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
|
|
430
|
+
WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
|
|
384
431
|
Please add "concurrent-ruby" to your Gemfile.
|
|
385
432
|
MESSAGE
|
|
386
433
|
raise
|
|
387
434
|
end
|
|
388
435
|
|
|
436
|
+
def parse_workers(value)
|
|
437
|
+
if value == :auto || value == 'auto'
|
|
438
|
+
require_processor_counter
|
|
439
|
+
Integer(::Concurrent.available_processor_count)
|
|
440
|
+
else
|
|
441
|
+
Integer(value)
|
|
442
|
+
end
|
|
443
|
+
rescue ArgumentError, TypeError
|
|
444
|
+
raise ArgumentError, "workers must be an Integer or :auto"
|
|
445
|
+
end
|
|
446
|
+
|
|
389
447
|
# Load and use the normal Rack builder if we can, otherwise
|
|
390
448
|
# fallback to our minimal version.
|
|
391
449
|
def rack_builder
|
|
@@ -426,6 +484,17 @@ module Puma
|
|
|
426
484
|
rack_app
|
|
427
485
|
end
|
|
428
486
|
|
|
487
|
+
def run_mode_hooks
|
|
488
|
+
workers_before = @_options[:workers]
|
|
489
|
+
key = workers_before > 0 ? :cluster : :single
|
|
490
|
+
|
|
491
|
+
@_options.all_of(key).each(&:call)
|
|
492
|
+
|
|
493
|
+
unless @_options[:workers] == workers_before
|
|
494
|
+
raise "cannot change the number of workers inside a #{key} configuration hook"
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
429
498
|
def set_conditional_default_options
|
|
430
499
|
@_options.default_options[:preload_app] = !@_options[:prune_bundler] &&
|
|
431
500
|
(@_options[:workers] > 1) && Puma.forkable?
|
data/lib/puma/const.rb
CHANGED
|
@@ -100,8 +100,8 @@ module Puma
|
|
|
100
100
|
# too taxing on performance.
|
|
101
101
|
module Const
|
|
102
102
|
|
|
103
|
-
PUMA_VERSION = VERSION = "
|
|
104
|
-
CODE_NAME = "
|
|
103
|
+
PUMA_VERSION = VERSION = "8.0.0"
|
|
104
|
+
CODE_NAME = "Into the Arena"
|
|
105
105
|
|
|
106
106
|
PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
|
|
107
107
|
|
data/lib/puma/control_cli.rb
CHANGED
data/lib/puma/detect.rb
CHANGED
|
@@ -35,6 +35,13 @@ module Puma
|
|
|
35
35
|
IS_WINDOWS
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
BACKTRACE_SIGNAL =
|
|
39
|
+
if Signal.list.key?("INFO")
|
|
40
|
+
"SIGINFO"
|
|
41
|
+
elsif Signal.list.key?("PWR")
|
|
42
|
+
"SIGPWR"
|
|
43
|
+
end
|
|
44
|
+
|
|
38
45
|
# @version 5.0.0
|
|
39
46
|
def self.mri?
|
|
40
47
|
IS_MRI
|
|
@@ -44,4 +51,8 @@ module Puma
|
|
|
44
51
|
def self.forkable?
|
|
45
52
|
HAS_FORK
|
|
46
53
|
end
|
|
54
|
+
|
|
55
|
+
def self.backtrace_signal
|
|
56
|
+
BACKTRACE_SIGNAL
|
|
57
|
+
end
|
|
47
58
|
end
|
data/lib/puma/dsl.rb
CHANGED
|
@@ -155,7 +155,7 @@ module Puma
|
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
def default_host
|
|
158
|
-
@options[:default_host] || Configuration
|
|
158
|
+
@options[:default_host] || Configuration.default_tcp_host
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
def inject(&blk)
|
|
@@ -216,6 +216,8 @@ module Puma
|
|
|
216
216
|
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
|
217
217
|
# @example
|
|
218
218
|
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
|
219
|
+
# @example
|
|
220
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
|
|
219
221
|
#
|
|
220
222
|
def activate_control_app(url="auto", opts={})
|
|
221
223
|
if url == "auto"
|
|
@@ -240,6 +242,7 @@ module Puma
|
|
|
240
242
|
|
|
241
243
|
@options[:control_auth_token] = auth_token
|
|
242
244
|
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
|
245
|
+
@options[:control_data_only] = opts[:data_only] if opts[:data_only]
|
|
243
246
|
end
|
|
244
247
|
|
|
245
248
|
# Load additional configuration from a file.
|
|
@@ -257,7 +260,8 @@ module Puma
|
|
|
257
260
|
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
|
|
258
261
|
# not overwrite previous bindings.
|
|
259
262
|
#
|
|
260
|
-
# The default is "tcp://
|
|
263
|
+
# The default is "tcp://[::]:9292" when IPv6 interfaces are available,
|
|
264
|
+
# otherwise "tcp://0.0.0.0:9292".
|
|
261
265
|
#
|
|
262
266
|
# You can use query parameters within the url to specify options:
|
|
263
267
|
#
|
|
@@ -276,7 +280,7 @@ module Puma
|
|
|
276
280
|
# @example SSL cert for mutual TLS (mTLS)
|
|
277
281
|
# bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem&ca=ca.pem&verify_mode=force_peer'
|
|
278
282
|
# @example Disable optimization for low latency
|
|
279
|
-
# bind 'tcp://
|
|
283
|
+
# bind 'tcp://[::]:9292?low_latency=false'
|
|
280
284
|
# @example Socket permissions
|
|
281
285
|
# bind 'unix:///var/run/puma.sock?umask=0111'
|
|
282
286
|
#
|
|
@@ -346,7 +350,7 @@ module Puma
|
|
|
346
350
|
|
|
347
351
|
# Define how long persistent connections can be idle before Puma closes them.
|
|
348
352
|
#
|
|
349
|
-
# The default is
|
|
353
|
+
# The default is 65 seconds.
|
|
350
354
|
#
|
|
351
355
|
# @example
|
|
352
356
|
# persistent_timeout 30
|
|
@@ -592,6 +596,29 @@ module Puma
|
|
|
592
596
|
@options[:max_threads] = max
|
|
593
597
|
end
|
|
594
598
|
|
|
599
|
+
# Configure the max number of IO threads.
|
|
600
|
+
#
|
|
601
|
+
# When request handlers know the current requests will no longer use a significant amount
|
|
602
|
+
# of CPU, they can mark the current request as IO bound using <tt>env["puma.mark_as_io_bound"]</tt>.
|
|
603
|
+
#
|
|
604
|
+
# Threads marked as IO bound are allowed to go over the max thread limit.
|
|
605
|
+
#
|
|
606
|
+
# @example
|
|
607
|
+
# threads 5
|
|
608
|
+
# max_io_threads 5
|
|
609
|
+
#
|
|
610
|
+
# The above example allows for 5 regular threads and 5 IO threads to process requests concurrently.
|
|
611
|
+
# Any IO thread over the limit is counted as a regular thread, hence the above configuration also
|
|
612
|
+
# allows for 3 regular threads and 7 IO threads for example.
|
|
613
|
+
def max_io_threads(max)
|
|
614
|
+
max = Integer(max)
|
|
615
|
+
if max < 0
|
|
616
|
+
raise "The maximum number of IO threads (#{max}) must be a positive number"
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
@options[:max_io_threads] = max
|
|
620
|
+
end
|
|
621
|
+
|
|
595
622
|
# Instead of using +bind+ and manually constructing a URI like:
|
|
596
623
|
#
|
|
597
624
|
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
|
|
@@ -666,21 +693,27 @@ module Puma
|
|
|
666
693
|
@options[:state_permission] = permission
|
|
667
694
|
end
|
|
668
695
|
|
|
669
|
-
# How many worker processes to run.
|
|
670
|
-
#
|
|
696
|
+
# How many worker processes to run. Typically this is set to the number of
|
|
697
|
+
# available cores.
|
|
671
698
|
#
|
|
672
699
|
# The default is the value of the environment variable +WEB_CONCURRENCY+ if
|
|
673
|
-
# set, otherwise 0.
|
|
700
|
+
# set, otherwise 0. Passing +:auto+ will set the value to
|
|
701
|
+
# +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
|
|
702
|
+
# On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
|
|
703
|
+
# will round down. If it rounds down to 0, Puma will run in single mode and
|
|
704
|
+
# cluster-only hooks like +before_worker_boot+ will not execute.
|
|
705
|
+
# If you rely on cluster-only hooks, set an explicit worker count.
|
|
674
706
|
#
|
|
675
|
-
#
|
|
707
|
+
# A value of 0 or nil means run in single mode.
|
|
676
708
|
#
|
|
677
709
|
# @example
|
|
678
710
|
# workers 2
|
|
711
|
+
# workers :auto
|
|
679
712
|
#
|
|
680
713
|
# @see Puma::Cluster
|
|
681
714
|
#
|
|
682
715
|
def workers(count)
|
|
683
|
-
@options[:workers] = count.
|
|
716
|
+
@options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
|
|
684
717
|
end
|
|
685
718
|
|
|
686
719
|
# Disable warning message when running in cluster mode with a single worker.
|
|
@@ -718,6 +751,44 @@ module Puma
|
|
|
718
751
|
@options[:silence_fork_callback_warning] = true
|
|
719
752
|
end
|
|
720
753
|
|
|
754
|
+
# Code to run only in single mode.
|
|
755
|
+
# Runs after all config files are loaded.
|
|
756
|
+
#
|
|
757
|
+
# This can be called multiple times.
|
|
758
|
+
#
|
|
759
|
+
# @note Single mode only.
|
|
760
|
+
#
|
|
761
|
+
# @example
|
|
762
|
+
# single do
|
|
763
|
+
# silence_fork_callback_warning
|
|
764
|
+
# end
|
|
765
|
+
#
|
|
766
|
+
def single(&block)
|
|
767
|
+
raise ArgumentError, "A block must be provided to `single`" unless block
|
|
768
|
+
|
|
769
|
+
@options[:single] ||= []
|
|
770
|
+
@options[:single] << block
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
# Code to run only in cluster mode.
|
|
774
|
+
# Runs after all config files are loaded.
|
|
775
|
+
#
|
|
776
|
+
# This can be called multiple times.
|
|
777
|
+
#
|
|
778
|
+
# @note Cluster mode only.
|
|
779
|
+
#
|
|
780
|
+
# @example
|
|
781
|
+
# cluster do
|
|
782
|
+
# prune_bundler
|
|
783
|
+
# end
|
|
784
|
+
#
|
|
785
|
+
def cluster(&block)
|
|
786
|
+
raise ArgumentError, "A block must be provided to `cluster`" unless block
|
|
787
|
+
|
|
788
|
+
@options[:cluster] ||= []
|
|
789
|
+
@options[:cluster] << block
|
|
790
|
+
end
|
|
791
|
+
|
|
721
792
|
# Code to run immediately before master process
|
|
722
793
|
# forks workers (once on boot). These hooks can block if necessary
|
|
723
794
|
# to wait for background operations unknown to Puma to finish before
|
|
@@ -995,6 +1066,7 @@ module Puma
|
|
|
995
1066
|
# The default is +true+ if your app uses more than 1 worker.
|
|
996
1067
|
#
|
|
997
1068
|
# @note Cluster mode only.
|
|
1069
|
+
# @note When using `fork_worker`, this only applies to worker 0.
|
|
998
1070
|
#
|
|
999
1071
|
# @example
|
|
1000
1072
|
# preload_app!
|
|
@@ -1030,6 +1102,7 @@ module Puma
|
|
|
1030
1102
|
# new Bundler context and thus can float around as the release
|
|
1031
1103
|
# dictates.
|
|
1032
1104
|
#
|
|
1105
|
+
# @note Cluster mode only.
|
|
1033
1106
|
# @note This is incompatible with +preload_app!+.
|
|
1034
1107
|
# @note This is only supported for RubyGems 2.2+
|
|
1035
1108
|
#
|
|
@@ -1135,7 +1208,7 @@ module Puma
|
|
|
1135
1208
|
|
|
1136
1209
|
# Change the default worker timeout for booting.
|
|
1137
1210
|
#
|
|
1138
|
-
# The default is
|
|
1211
|
+
# The default is 60 seconds.
|
|
1139
1212
|
#
|
|
1140
1213
|
# @note Cluster mode only.
|
|
1141
1214
|
#
|
|
@@ -1217,11 +1290,14 @@ module Puma
|
|
|
1217
1290
|
# threads will be written to $stdout. This can help figure
|
|
1218
1291
|
# out why shutdown is hanging.
|
|
1219
1292
|
#
|
|
1220
|
-
|
|
1221
|
-
|
|
1293
|
+
# If `on_force` is true, the backtraces will be written only
|
|
1294
|
+
# when the shutdown is forced i.e. not graceful.
|
|
1295
|
+
#
|
|
1296
|
+
# @see force_shutdown_after
|
|
1297
|
+
def shutdown_debug(val = true, on_force: false)
|
|
1298
|
+
@options[:shutdown_debug] = val && on_force ? :on_force : val
|
|
1222
1299
|
end
|
|
1223
1300
|
|
|
1224
|
-
|
|
1225
1301
|
# Maximum delay of worker accept loop.
|
|
1226
1302
|
#
|
|
1227
1303
|
# Attempts to route traffic to less-busy workers by causing a busy worker to delay
|
|
@@ -1378,7 +1454,7 @@ module Puma
|
|
|
1378
1454
|
#
|
|
1379
1455
|
# The default is +:auto+.
|
|
1380
1456
|
#
|
|
1381
|
-
# @see https://github.com/socketry/nio4r/blob/
|
|
1457
|
+
# @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
|
|
1382
1458
|
#
|
|
1383
1459
|
def io_selector_backend(backend)
|
|
1384
1460
|
@options[:io_selector_backend] = backend.to_sym
|
data/lib/puma/launcher.rb
CHANGED
|
@@ -42,9 +42,11 @@ module Puma
|
|
|
42
42
|
# end
|
|
43
43
|
# Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
|
|
44
44
|
def initialize(conf, launcher_args={})
|
|
45
|
-
## Minimal initialization
|
|
45
|
+
## Minimal initialization before potential early restart (e.g. from bundle pruning)
|
|
46
46
|
|
|
47
47
|
@config = conf
|
|
48
|
+
# Advertise the CLI Configuration before config files are loaded
|
|
49
|
+
Puma.cli_config = @config if defined?(Puma.cli_config)
|
|
48
50
|
@config.clamp
|
|
49
51
|
|
|
50
52
|
@options = @config.options
|
|
@@ -70,8 +72,7 @@ module Puma
|
|
|
70
72
|
|
|
71
73
|
env = launcher_args.delete(:env) || ENV
|
|
72
74
|
|
|
73
|
-
#
|
|
74
|
-
Puma.cli_config = @config if defined?(Puma.cli_config)
|
|
75
|
+
# Log after prune_bundler! to avoid duplicate logging if a restart occurs
|
|
75
76
|
log_config if env['PUMA_LOG_CONFIG']
|
|
76
77
|
|
|
77
78
|
@binder = Binder.new(@log_writer, @options)
|
|
@@ -475,8 +476,8 @@ module Puma
|
|
|
475
476
|
end
|
|
476
477
|
|
|
477
478
|
begin
|
|
478
|
-
|
|
479
|
-
Signal.trap
|
|
479
|
+
if Puma.backtrace_signal
|
|
480
|
+
Signal.trap Puma.backtrace_signal do
|
|
480
481
|
thread_status do |name, backtrace|
|
|
481
482
|
@log_writer.log(name)
|
|
482
483
|
@log_writer.log(backtrace.map { |bt| " #{bt}" })
|
|
@@ -484,8 +485,7 @@ module Puma
|
|
|
484
485
|
end
|
|
485
486
|
end
|
|
486
487
|
rescue Exception
|
|
487
|
-
|
|
488
|
-
# to see this constantly on Linux.
|
|
488
|
+
log "*** SIGINFO/SIGPWR not implemented, signal based backtrace unavailable!"
|
|
489
489
|
end
|
|
490
490
|
end
|
|
491
491
|
|
data/lib/puma/puma_http11.jar
CHANGED
|
Binary file
|
data/lib/puma/reactor.rb
CHANGED
|
@@ -75,15 +75,12 @@ module Puma
|
|
|
75
75
|
private
|
|
76
76
|
|
|
77
77
|
def select_loop
|
|
78
|
-
close_selector = true
|
|
79
78
|
begin
|
|
80
79
|
until @input.closed? && @input.empty?
|
|
81
80
|
# Wakeup any registered object that receives incoming data.
|
|
82
81
|
# Block until the earliest timeout or Selector#wakeup is called.
|
|
83
82
|
timeout = (earliest = @timeouts.first) && earliest.timeout
|
|
84
|
-
monitor_wake_up = false
|
|
85
83
|
@selector.select(timeout) do |monitor|
|
|
86
|
-
monitor_wake_up = true
|
|
87
84
|
wakeup!(monitor.value)
|
|
88
85
|
end
|
|
89
86
|
|
|
@@ -103,18 +100,12 @@ module Puma
|
|
|
103
100
|
STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
|
|
104
101
|
STDERR.puts e.backtrace
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
# is odd. Regardless, it may continue for thousands of calls if retried.
|
|
108
|
-
# Also, when it raises, @selector.close also raises an error.
|
|
109
|
-
if !monitor_wake_up && NoMethodError === e
|
|
110
|
-
close_selector = false
|
|
111
|
-
else
|
|
112
|
-
retry
|
|
113
|
-
end
|
|
103
|
+
retry
|
|
114
104
|
end
|
|
105
|
+
|
|
115
106
|
# Wakeup all remaining objects on shutdown.
|
|
116
107
|
@timeouts.each(&@block)
|
|
117
|
-
@selector.close
|
|
108
|
+
@selector.close
|
|
118
109
|
end
|
|
119
110
|
|
|
120
111
|
# Start monitoring the object.
|