puma 5.2.2-java → 5.4.0-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.
- checksums.yaml +4 -4
- data/History.md +104 -1
- data/README.md +1 -1
- data/docs/architecture.md +5 -4
- data/docs/deployment.md +3 -18
- data/docs/jungle/rc.d/README.md +1 -1
- data/docs/kubernetes.md +1 -1
- data/docs/plugins.md +1 -1
- data/docs/restart.md +1 -1
- data/docs/stats.md +1 -1
- data/docs/systemd.md +1 -1
- data/ext/puma_http11/extconf.rb +18 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/mini_ssl.c +16 -1
- data/lib/puma.rb +18 -2
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +33 -22
- data/lib/puma/client.rb +9 -7
- data/lib/puma/cluster.rb +41 -11
- data/lib/puma/cluster/worker.rb +9 -2
- data/lib/puma/cluster/worker_handle.rb +4 -0
- data/lib/puma/configuration.rb +3 -0
- data/lib/puma/const.rb +3 -3
- data/lib/puma/control_cli.rb +3 -1
- data/lib/puma/dsl.rb +26 -1
- data/lib/puma/error_logger.rb +2 -2
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/plugin.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/queue_close.rb +7 -7
- data/lib/puma/rack/builder.rb +1 -1
- data/lib/puma/request.rb +25 -9
- data/lib/puma/server.rb +30 -43
- data/lib/puma/thread_pool.rb +10 -7
- data/lib/puma/util.rb +1 -1
- metadata +5 -5
data/lib/puma/client.rb
CHANGED
@@ -69,6 +69,7 @@ module Puma
|
|
69
69
|
@hijacked = false
|
70
70
|
|
71
71
|
@peerip = nil
|
72
|
+
@listener = nil
|
72
73
|
@remote_addr_header = nil
|
73
74
|
|
74
75
|
@body_remain = 0
|
@@ -81,7 +82,7 @@ module Puma
|
|
81
82
|
|
82
83
|
attr_writer :peerip
|
83
84
|
|
84
|
-
attr_accessor :remote_addr_header
|
85
|
+
attr_accessor :remote_addr_header, :listener
|
85
86
|
|
86
87
|
def_delegators :@io, :closed?
|
87
88
|
|
@@ -126,7 +127,7 @@ module Puma
|
|
126
127
|
@parsed_bytes = 0
|
127
128
|
@ready = false
|
128
129
|
@body_remain = 0
|
129
|
-
@peerip = nil
|
130
|
+
@peerip = nil if @remote_addr_header
|
130
131
|
@in_last_chunk = false
|
131
132
|
|
132
133
|
if @buffer
|
@@ -142,8 +143,7 @@ module Puma
|
|
142
143
|
return false
|
143
144
|
else
|
144
145
|
begin
|
145
|
-
if fast_check &&
|
146
|
-
IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
|
146
|
+
if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
|
147
147
|
return try_to_finish
|
148
148
|
end
|
149
149
|
rescue IOError
|
@@ -201,13 +201,13 @@ module Puma
|
|
201
201
|
|
202
202
|
def eagerly_finish
|
203
203
|
return true if @ready
|
204
|
-
return false unless
|
204
|
+
return false unless @to_io.wait_readable(0)
|
205
205
|
try_to_finish
|
206
206
|
end
|
207
207
|
|
208
208
|
def finish(timeout)
|
209
209
|
return if @ready
|
210
|
-
|
210
|
+
@to_io.wait_readable(timeout) || timeout! until try_to_finish
|
211
211
|
end
|
212
212
|
|
213
213
|
def timeout!
|
@@ -295,6 +295,7 @@ module Puma
|
|
295
295
|
|
296
296
|
if remain > MAX_BODY
|
297
297
|
@body = Tempfile.new(Const::PUMA_TMP_BASE)
|
298
|
+
@body.unlink
|
298
299
|
@body.binmode
|
299
300
|
@tempfile = @body
|
300
301
|
else
|
@@ -307,7 +308,7 @@ module Puma
|
|
307
308
|
|
308
309
|
@body_remain = remain
|
309
310
|
|
310
|
-
|
311
|
+
false
|
311
312
|
end
|
312
313
|
|
313
314
|
def read_body
|
@@ -386,6 +387,7 @@ module Puma
|
|
386
387
|
@prev_chunk = ""
|
387
388
|
|
388
389
|
@body = Tempfile.new(Const::PUMA_TMP_BASE)
|
390
|
+
@body.unlink
|
389
391
|
@body.binmode
|
390
392
|
@tempfile = @body
|
391
393
|
@chunked_content_length = 0
|
data/lib/puma/cluster.rb
CHANGED
@@ -43,6 +43,7 @@ module Puma
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def start_phased_restart
|
46
|
+
@events.fire_on_restart!
|
46
47
|
@phase += 1
|
47
48
|
log "- Starting phased worker restart, phase: #{@phase}"
|
48
49
|
|
@@ -317,7 +318,7 @@ module Puma
|
|
317
318
|
|
318
319
|
stop_workers
|
319
320
|
stop
|
320
|
-
|
321
|
+
@events.fire_on_stopped!
|
321
322
|
raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
|
322
323
|
exit 0 # Clean exit, workers were stopped
|
323
324
|
end
|
@@ -332,16 +333,22 @@ module Puma
|
|
332
333
|
# This is aligned with the output from Runner, see Runner#output_header
|
333
334
|
log "* Workers: #{@options[:workers]}"
|
334
335
|
|
335
|
-
# Threads explicitly marked as fork safe will be ignored.
|
336
|
-
# Used in Rails, but may be used by anyone.
|
337
|
-
before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
338
|
-
|
339
336
|
if preload?
|
337
|
+
# Threads explicitly marked as fork safe will be ignored. Used in Rails,
|
338
|
+
# but may be used by anyone. Note that we need to explicit
|
339
|
+
# Process::Waiter check here because there's a bug in Ruby 2.6 and below
|
340
|
+
# where calling thread_variable_get on a Process::Waiter will segfault.
|
341
|
+
# We can drop that clause once those versions of Ruby are no longer
|
342
|
+
# supported.
|
343
|
+
fork_safe = ->(t) { !t.is_a?(Process::Waiter) && t.thread_variable_get(:fork_safe) }
|
344
|
+
|
345
|
+
before = Thread.list.reject(&fork_safe)
|
346
|
+
|
340
347
|
log "* Restarts: (\u2714) hot (\u2716) phased"
|
341
348
|
log "* Preloading application"
|
342
349
|
load_and_bind
|
343
350
|
|
344
|
-
after = Thread.list.reject
|
351
|
+
after = Thread.list.reject(&fork_safe)
|
345
352
|
|
346
353
|
if after.size > before.size
|
347
354
|
threads = (after - before)
|
@@ -382,6 +389,8 @@ module Puma
|
|
382
389
|
|
383
390
|
log "Use Ctrl-C to stop"
|
384
391
|
|
392
|
+
single_worker_warning
|
393
|
+
|
385
394
|
redirect_io
|
386
395
|
|
387
396
|
Plugins.fire_background
|
@@ -403,19 +412,21 @@ module Puma
|
|
403
412
|
|
404
413
|
begin
|
405
414
|
booted = false
|
415
|
+
in_phased_restart = false
|
416
|
+
workers_not_booted = @options[:workers]
|
406
417
|
|
407
418
|
while @status == :run
|
408
419
|
begin
|
409
420
|
if @phased_restart
|
410
421
|
start_phased_restart
|
411
422
|
@phased_restart = false
|
423
|
+
in_phased_restart = true
|
424
|
+
workers_not_booted = @options[:workers]
|
412
425
|
end
|
413
426
|
|
414
427
|
check_workers
|
415
428
|
|
416
|
-
|
417
|
-
|
418
|
-
if res
|
429
|
+
if read.wait_readable([0, @next_check - Time.now].max)
|
419
430
|
req = read.read_nonblock(1)
|
420
431
|
|
421
432
|
@next_check = Time.now if req == "!"
|
@@ -434,8 +445,9 @@ module Puma
|
|
434
445
|
case req
|
435
446
|
when "b"
|
436
447
|
w.boot!
|
437
|
-
log "- Worker #{w.index} (PID: #{pid}) booted, phase: #{w.phase}"
|
448
|
+
log "- Worker #{w.index} (PID: #{pid}) booted in #{w.uptime.round(2)}s, phase: #{w.phase}"
|
438
449
|
@next_check = Time.now
|
450
|
+
workers_not_booted -= 1
|
439
451
|
when "e"
|
440
452
|
# external term, see worker method, Signal.trap "SIGTERM"
|
441
453
|
w.instance_variable_set :@term, true
|
@@ -453,6 +465,10 @@ module Puma
|
|
453
465
|
log "! Out-of-sync worker list, no #{pid} worker"
|
454
466
|
end
|
455
467
|
end
|
468
|
+
if in_phased_restart && workers_not_booted.zero?
|
469
|
+
@events.fire_on_booted!
|
470
|
+
in_phased_restart = false
|
471
|
+
end
|
456
472
|
|
457
473
|
rescue Interrupt
|
458
474
|
@status = :stop
|
@@ -470,6 +486,15 @@ module Puma
|
|
470
486
|
|
471
487
|
private
|
472
488
|
|
489
|
+
def single_worker_warning
|
490
|
+
return if @options[:workers] != 1 || @options[:silence_single_worker_warning]
|
491
|
+
|
492
|
+
log "! WARNING: Detected running cluster mode with 1 worker."
|
493
|
+
log "! Running Puma in cluster mode with a single worker is often a misconfiguration."
|
494
|
+
log "! Consider running Puma in single-mode (workers = 0) in order to reduce memory overhead."
|
495
|
+
log "! Set the `silence_single_worker_warning` option to silence this warning message."
|
496
|
+
end
|
497
|
+
|
473
498
|
# loops thru @workers, removing workers that exited, and calling
|
474
499
|
# `#term` if needed
|
475
500
|
def wait_workers
|
@@ -499,7 +524,12 @@ module Puma
|
|
499
524
|
def timeout_workers
|
500
525
|
@workers.each do |w|
|
501
526
|
if !w.term? && w.ping_timeout <= Time.now
|
502
|
-
|
527
|
+
details = if w.booted?
|
528
|
+
"(worker failed to check in within #{@options[:worker_timeout]} seconds)"
|
529
|
+
else
|
530
|
+
"(worker failed to boot within #{@options[:worker_boot_timeout]} seconds)"
|
531
|
+
end
|
532
|
+
log "! Terminating timed out worker #{details}: #{w.pid}"
|
503
533
|
w.kill
|
504
534
|
end
|
505
535
|
end
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -33,9 +33,9 @@ module Puma
|
|
33
33
|
Signal.trap "SIGINT", "IGNORE"
|
34
34
|
Signal.trap "SIGCHLD", "DEFAULT"
|
35
35
|
|
36
|
-
|
36
|
+
Thread.new do
|
37
37
|
Puma.set_thread_name "worker check pipe"
|
38
|
-
|
38
|
+
@check_pipe.wait_readable
|
39
39
|
log "! Detected parent died, dying"
|
40
40
|
exit! 1
|
41
41
|
end
|
@@ -54,7 +54,14 @@ module Puma
|
|
54
54
|
# things in shape before booting the app.
|
55
55
|
@launcher.config.run_hooks :before_worker_boot, index, @launcher.events
|
56
56
|
|
57
|
+
begin
|
57
58
|
server = @server ||= start_server
|
59
|
+
rescue Exception => e
|
60
|
+
log "! Unable to start worker"
|
61
|
+
log e.backtrace[0]
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
58
65
|
restart_server = Queue.new << true << false
|
59
66
|
|
60
67
|
fork_worker = @options[:fork_worker] && index == 0
|
data/lib/puma/configuration.rb
CHANGED
@@ -193,6 +193,7 @@ module Puma
|
|
193
193
|
:debug => false,
|
194
194
|
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
195
195
|
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
196
|
+
:silence_single_worker_warning => false,
|
196
197
|
:mode => :http,
|
197
198
|
:worker_timeout => DefaultWorkerTimeout,
|
198
199
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
@@ -342,6 +343,8 @@ module Puma
|
|
342
343
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
343
344
|
|
344
345
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
346
|
+
rack_options = rack_options || {}
|
347
|
+
|
345
348
|
@options.file_options.merge!(rack_options)
|
346
349
|
|
347
350
|
config_ru_binds = []
|
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 = "5.
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "5.4.0".freeze
|
104
|
+
CODE_NAME = "Super Flight".freeze
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
107
107
|
|
@@ -235,7 +235,7 @@ module Puma
|
|
235
235
|
|
236
236
|
EARLY_HINTS = "rack.early_hints".freeze
|
237
237
|
|
238
|
-
#
|
238
|
+
# Minimum interval to checks worker health
|
239
239
|
WORKER_CHECK_INTERVAL = 5
|
240
240
|
|
241
241
|
# Illegal character in the key or value of response header
|
data/lib/puma/control_cli.rb
CHANGED
@@ -176,7 +176,9 @@ module Puma
|
|
176
176
|
when 'tcp'
|
177
177
|
TCPSocket.new uri.host, uri.port
|
178
178
|
when 'unix'
|
179
|
-
UNIXSocket
|
179
|
+
# check for abstract UNIXSocket
|
180
|
+
UNIXSocket.new(@control_url.start_with?('unix://@') ?
|
181
|
+
"\0#{uri.host}#{uri.path}" : "#{uri.host}#{uri.path}")
|
180
182
|
else
|
181
183
|
raise "Invalid scheme: #{uri.scheme}"
|
182
184
|
end
|
data/lib/puma/dsl.rb
CHANGED
@@ -201,7 +201,7 @@ module Puma
|
|
201
201
|
# * Set the socket backlog depth with +backlog+, default is 1024.
|
202
202
|
# * Set up an SSL certificate with +key+ & +cert+.
|
203
203
|
# * Set whether to optimize for low latency instead of throughput with
|
204
|
-
# +low_latency+, default is to optimize for low latency. This is done
|
204
|
+
# +low_latency+, default is to not optimize for low latency. This is done
|
205
205
|
# via +Socket::TCP_NODELAY+.
|
206
206
|
# * Set socket permissions with +umask+.
|
207
207
|
#
|
@@ -381,6 +381,13 @@ module Puma
|
|
381
381
|
@options[:rackup] ||= path.to_s
|
382
382
|
end
|
383
383
|
|
384
|
+
# Allows setting `env['rack.url_scheme']`.
|
385
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
386
|
+
# Normal values are 'http' or 'https'.
|
387
|
+
def rack_url_scheme(scheme=nil)
|
388
|
+
@options[:rack_url_scheme] = scheme
|
389
|
+
end
|
390
|
+
|
384
391
|
def early_hints(answer=true)
|
385
392
|
@options[:early_hints] = answer
|
386
393
|
end
|
@@ -482,6 +489,24 @@ module Puma
|
|
482
489
|
@options[:workers] = count.to_i
|
483
490
|
end
|
484
491
|
|
492
|
+
# Disable warning message when running in cluster mode with a single worker.
|
493
|
+
#
|
494
|
+
# Cluster mode has some overhead of running an additional 'control' process
|
495
|
+
# in order to manage the cluster. If only running a single worker it is
|
496
|
+
# likely not worth paying that overhead vs running in single mode with
|
497
|
+
# additional threads instead.
|
498
|
+
#
|
499
|
+
# There are some scenarios where running cluster mode with a single worker
|
500
|
+
# may still be warranted and valid under certain deployment scenarios, see
|
501
|
+
# https://github.com/puma/puma/issues/2534
|
502
|
+
#
|
503
|
+
# Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
|
504
|
+
#
|
505
|
+
# @note Cluster mode only.
|
506
|
+
def silence_single_worker_warning
|
507
|
+
@options[:silence_single_worker_warning] = true
|
508
|
+
end
|
509
|
+
|
485
510
|
# Code to run immediately before master process
|
486
511
|
# forks workers (once on boot). These hooks can block if necessary
|
487
512
|
# to wait for background operations unknown to Puma to finish before
|
data/lib/puma/error_logger.rb
CHANGED
@@ -23,7 +23,7 @@ module Puma
|
|
23
23
|
new $stderr
|
24
24
|
end
|
25
25
|
|
26
|
-
# Print
|
26
|
+
# Print occurred error details.
|
27
27
|
# +options+ hash with additional options:
|
28
28
|
# - +error+ is an exception object
|
29
29
|
# - +req+ the http request
|
@@ -34,7 +34,7 @@ module Puma
|
|
34
34
|
log title(options)
|
35
35
|
end
|
36
36
|
|
37
|
-
# Print
|
37
|
+
# Print occurred error details only if
|
38
38
|
# environment variable PUMA_DEBUG is defined.
|
39
39
|
# +options+ hash with additional options:
|
40
40
|
# - +error+ is an exception object
|
@@ -17,7 +17,7 @@ module Puma
|
|
17
17
|
# be particularly full-featured or fast. It just has to handle the few places
|
18
18
|
# where Puma relies on JSON serialization internally.
|
19
19
|
|
20
|
-
module
|
20
|
+
module JSONSerialization
|
21
21
|
QUOTE = /"/
|
22
22
|
BACKSLASH = /\\/
|
23
23
|
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
data/lib/puma/minissl.rb
CHANGED
@@ -162,7 +162,7 @@ module Puma
|
|
162
162
|
end
|
163
163
|
|
164
164
|
def read_and_drop(timeout = 1)
|
165
|
-
return :timeout unless
|
165
|
+
return :timeout unless @socket.wait_readable(timeout)
|
166
166
|
case @socket.read_nonblock(1024, exception: false)
|
167
167
|
when nil
|
168
168
|
:eof
|
data/lib/puma/plugin.rb
CHANGED
data/lib/puma/puma_http11.jar
CHANGED
Binary file
|
data/lib/puma/queue_close.rb
CHANGED
@@ -5,22 +5,22 @@ module Puma
|
|
5
5
|
# Add a simple implementation for earlier Ruby versions.
|
6
6
|
#
|
7
7
|
module QueueClose
|
8
|
-
def initialize
|
9
|
-
@closed = false
|
10
|
-
super
|
11
|
-
end
|
12
8
|
def close
|
9
|
+
num_waiting.times {push nil}
|
13
10
|
@closed = true
|
14
11
|
end
|
15
12
|
def closed?
|
16
|
-
@closed
|
13
|
+
@closed ||= false
|
17
14
|
end
|
18
15
|
def push(object)
|
19
|
-
|
20
|
-
raise ClosedQueueError if @closed
|
16
|
+
raise ClosedQueueError if closed?
|
21
17
|
super
|
22
18
|
end
|
23
19
|
alias << push
|
20
|
+
def pop(non_block=false)
|
21
|
+
return nil if !non_block && closed? && empty?
|
22
|
+
super
|
23
|
+
end
|
24
24
|
end
|
25
25
|
::Queue.prepend QueueClose
|
26
26
|
end
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/request.rb
CHANGED
@@ -26,9 +26,10 @@ module Puma
|
|
26
26
|
# Finally, it'll return +true+ on keep-alive connections.
|
27
27
|
# @param client [Puma::Client]
|
28
28
|
# @param lines [Puma::IOBuffer]
|
29
|
+
# @param requests [Integer]
|
29
30
|
# @return [Boolean,:async]
|
30
31
|
#
|
31
|
-
def handle_request(client, lines)
|
32
|
+
def handle_request(client, lines, requests)
|
32
33
|
env = client.env
|
33
34
|
io = client.io # io may be a MiniSSL::Socket
|
34
35
|
|
@@ -50,7 +51,7 @@ module Puma
|
|
50
51
|
head = env[REQUEST_METHOD] == HEAD
|
51
52
|
|
52
53
|
env[RACK_INPUT] = body
|
53
|
-
env[RACK_URL_SCHEME]
|
54
|
+
env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
|
54
55
|
|
55
56
|
if @early_hints
|
56
57
|
env[EARLY_HINTS] = lambda { |headers|
|
@@ -110,7 +111,7 @@ module Puma
|
|
110
111
|
|
111
112
|
cork_socket io
|
112
113
|
|
113
|
-
str_headers(env, status, headers, res_info, lines)
|
114
|
+
str_headers(env, status, headers, res_info, lines, requests, client)
|
114
115
|
|
115
116
|
line_ending = LINE_END
|
116
117
|
|
@@ -148,8 +149,9 @@ module Puma
|
|
148
149
|
res_body.each do |part|
|
149
150
|
next if part.bytesize.zero?
|
150
151
|
if chunked
|
151
|
-
|
152
|
-
|
152
|
+
fast_write io, (part.bytesize.to_s(16) << line_ending)
|
153
|
+
fast_write io, part # part may have different encoding
|
154
|
+
fast_write io, line_ending
|
153
155
|
else
|
154
156
|
fast_write io, part
|
155
157
|
end
|
@@ -174,7 +176,7 @@ module Puma
|
|
174
176
|
after_reply.each { |o| o.call }
|
175
177
|
end
|
176
178
|
|
177
|
-
|
179
|
+
res_info[:keep_alive]
|
178
180
|
end
|
179
181
|
|
180
182
|
# @param env [Hash] see Puma::Client#env, from request
|
@@ -199,7 +201,7 @@ module Puma
|
|
199
201
|
begin
|
200
202
|
n = io.syswrite str
|
201
203
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
202
|
-
|
204
|
+
unless io.wait_writable WRITE_TIMEOUT
|
203
205
|
raise ConnectionError, "Socket timeout writing data"
|
204
206
|
end
|
205
207
|
|
@@ -230,7 +232,11 @@ module Puma
|
|
230
232
|
#
|
231
233
|
def normalize_env(env, client)
|
232
234
|
if host = env[HTTP_HOST]
|
233
|
-
|
235
|
+
# host can be a hostname, ipv4 or bracketed ipv6. Followed by an optional port.
|
236
|
+
if colon = host.rindex("]:") # IPV6 with port
|
237
|
+
env[SERVER_NAME] = host[0, colon+1]
|
238
|
+
env[SERVER_PORT] = host[colon+2, host.bytesize]
|
239
|
+
elsif !host.start_with?("[") && colon = host.index(":") # not hostname or IPV4 with port
|
234
240
|
env[SERVER_NAME] = host[0, colon]
|
235
241
|
env[SERVER_PORT] = host[colon+1, host.bytesize]
|
236
242
|
else
|
@@ -362,9 +368,11 @@ module Puma
|
|
362
368
|
# @param headers [Hash] the headers returned by the Rack application
|
363
369
|
# @param res_info [Hash] used to pass info between this method and #handle_request
|
364
370
|
# @param lines [Puma::IOBuffer] modified inn place
|
371
|
+
# @param requests [Integer] number of inline requests handled
|
372
|
+
# @param client [Puma::Client]
|
365
373
|
# @version 5.0.3
|
366
374
|
#
|
367
|
-
def str_headers(env, status, headers, res_info, lines)
|
375
|
+
def str_headers(env, status, headers, res_info, lines, requests, client)
|
368
376
|
line_ending = LINE_END
|
369
377
|
colon = COLON
|
370
378
|
|
@@ -405,6 +413,14 @@ module Puma
|
|
405
413
|
# if running without request queueing
|
406
414
|
res_info[:keep_alive] &&= @queue_requests
|
407
415
|
|
416
|
+
# Close the connection after a reasonable number of inline requests
|
417
|
+
# if the server is at capacity and the listener has a new connection ready.
|
418
|
+
# This allows Puma to service connections fairly when the number
|
419
|
+
# of concurrent connections exceeds the size of the threadpool.
|
420
|
+
res_info[:keep_alive] &&= requests < @max_fast_inline ||
|
421
|
+
@thread_pool.busy_threads < @max_threads ||
|
422
|
+
!client.listener.to_io.wait_readable(0)
|
423
|
+
|
408
424
|
res_info[:response_hijack] = nil
|
409
425
|
|
410
426
|
headers.each do |k, vs|
|