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/server.rb
CHANGED
@@ -14,6 +14,7 @@ require 'puma/io_buffer'
|
|
14
14
|
require 'puma/request'
|
15
15
|
|
16
16
|
require 'socket'
|
17
|
+
require 'io/wait'
|
17
18
|
require 'forwardable'
|
18
19
|
|
19
20
|
module Puma
|
@@ -137,8 +138,6 @@ module Puma
|
|
137
138
|
# socket parameter may be an MiniSSL::Socket, so use to_io
|
138
139
|
#
|
139
140
|
if tcp_cork_supported?
|
140
|
-
UNPACK_TCP_STATE_FROM_TCP_INFO = "C".freeze
|
141
|
-
|
142
141
|
# 6 == Socket::IPPROTO_TCP
|
143
142
|
# 3 == TCP_CORK
|
144
143
|
# 1/0 == turn on/off
|
@@ -168,12 +167,14 @@ module Puma
|
|
168
167
|
end
|
169
168
|
|
170
169
|
if closed_socket_supported?
|
170
|
+
UNPACK_TCP_STATE_FROM_TCP_INFO = "C".freeze
|
171
|
+
|
171
172
|
def closed_socket?(socket)
|
172
|
-
|
173
|
-
return false unless @precheck_closing
|
173
|
+
skt = socket.to_io
|
174
|
+
return false unless skt.kind_of?(TCPSocket) && @precheck_closing
|
174
175
|
|
175
176
|
begin
|
176
|
-
tcp_info =
|
177
|
+
tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
|
177
178
|
rescue IOError, SystemCallError
|
178
179
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
179
180
|
@precheck_closing = false
|
@@ -227,6 +228,7 @@ module Puma
|
|
227
228
|
@status = :run
|
228
229
|
|
229
230
|
@thread_pool = ThreadPool.new(
|
231
|
+
thread_name,
|
230
232
|
@min_threads,
|
231
233
|
@max_threads,
|
232
234
|
::Puma::IOBuffer,
|
@@ -295,6 +297,9 @@ module Puma
|
|
295
297
|
@thread_pool << client
|
296
298
|
elsif shutdown || client.timeout == 0
|
297
299
|
client.timeout!
|
300
|
+
else
|
301
|
+
client.set_timeout(@first_data_timeout)
|
302
|
+
false
|
298
303
|
end
|
299
304
|
rescue StandardError => e
|
300
305
|
client_error(e, client)
|
@@ -308,6 +313,7 @@ module Puma
|
|
308
313
|
sockets = [check] + @binder.ios
|
309
314
|
pool = @thread_pool
|
310
315
|
queue_requests = @queue_requests
|
316
|
+
drain = @options[:drain_on_shutdown] ? 0 : nil
|
311
317
|
|
312
318
|
remote_addr_value = nil
|
313
319
|
remote_addr_header = nil
|
@@ -319,23 +325,25 @@ module Puma
|
|
319
325
|
remote_addr_header = @options[:remote_address_header]
|
320
326
|
end
|
321
327
|
|
322
|
-
while @status == :run
|
328
|
+
while @status == :run || (drain && shutting_down?)
|
323
329
|
begin
|
324
|
-
ios = IO.select sockets
|
330
|
+
ios = IO.select sockets, nil, nil, (shutting_down? ? 0 : nil)
|
331
|
+
break unless ios
|
325
332
|
ios.first.each do |sock|
|
326
333
|
if sock == check
|
327
334
|
break if handle_check
|
328
335
|
else
|
329
336
|
pool.wait_until_not_full
|
330
|
-
pool.wait_for_less_busy_worker(
|
331
|
-
@options[:wait_for_less_busy_worker].to_f)
|
337
|
+
pool.wait_for_less_busy_worker(@options[:wait_for_less_busy_worker])
|
332
338
|
|
333
339
|
io = begin
|
334
340
|
sock.accept_nonblock
|
335
341
|
rescue IO::WaitReadable
|
336
342
|
next
|
337
343
|
end
|
344
|
+
drain += 1 if shutting_down?
|
338
345
|
client = Client.new io, @binder.env(sock)
|
346
|
+
client.listener = sock
|
339
347
|
if remote_addr_value
|
340
348
|
client.peerip = remote_addr_value
|
341
349
|
elsif remote_addr_header
|
@@ -349,6 +357,7 @@ module Puma
|
|
349
357
|
end
|
350
358
|
end
|
351
359
|
|
360
|
+
@events.debug "Drained #{drain} additional connections." if drain
|
352
361
|
@events.fire :state, @status
|
353
362
|
|
354
363
|
if queue_requests
|
@@ -389,7 +398,7 @@ module Puma
|
|
389
398
|
return true
|
390
399
|
end
|
391
400
|
|
392
|
-
|
401
|
+
false
|
393
402
|
end
|
394
403
|
|
395
404
|
# Given a connection on +client+, handle the incoming requests,
|
@@ -428,7 +437,7 @@ module Puma
|
|
428
437
|
|
429
438
|
while true
|
430
439
|
@requests_count += 1
|
431
|
-
case handle_request(client, buffer)
|
440
|
+
case handle_request(client, buffer, requests + 1)
|
432
441
|
when false
|
433
442
|
break
|
434
443
|
when :async
|
@@ -441,18 +450,17 @@ module Puma
|
|
441
450
|
|
442
451
|
requests += 1
|
443
452
|
|
444
|
-
|
453
|
+
# As an optimization, try to read the next request from the
|
454
|
+
# socket for a short time before returning to the reactor.
|
455
|
+
fast_check = @status == :run
|
445
456
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
# one once every max_fast_inline requests.
|
451
|
-
check_for_more_data = false
|
452
|
-
end
|
457
|
+
# Always pass the client back to the reactor after a reasonable
|
458
|
+
# number of inline requests if there are other requests pending.
|
459
|
+
fast_check = false if requests >= @max_fast_inline &&
|
460
|
+
@thread_pool.backlog > 0
|
453
461
|
|
454
462
|
next_request_ready = with_force_shutdown(client) do
|
455
|
-
client.reset(
|
463
|
+
client.reset(fast_check)
|
456
464
|
end
|
457
465
|
|
458
466
|
unless next_request_ready
|
@@ -526,7 +534,8 @@ module Puma
|
|
526
534
|
end
|
527
535
|
|
528
536
|
if @leak_stack_on_error
|
529
|
-
|
537
|
+
backtrace = e.backtrace.nil? ? '<no backtrace available>' : e.backtrace.join("\n")
|
538
|
+
[status, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{backtrace}"]]
|
530
539
|
else
|
531
540
|
[status, {}, ["An unhandled lowlevel error occurred. The application logs may have details.\n"]]
|
532
541
|
end
|
@@ -550,28 +559,6 @@ module Puma
|
|
550
559
|
$stdout.syswrite "#{pid}: === End thread backtrace dump ===\n"
|
551
560
|
end
|
552
561
|
|
553
|
-
if @options[:drain_on_shutdown]
|
554
|
-
count = 0
|
555
|
-
|
556
|
-
while true
|
557
|
-
ios = IO.select @binder.ios, nil, nil, 0
|
558
|
-
break unless ios
|
559
|
-
|
560
|
-
ios.first.each do |sock|
|
561
|
-
begin
|
562
|
-
if io = sock.accept_nonblock
|
563
|
-
count += 1
|
564
|
-
client = Client.new io, @binder.env(sock)
|
565
|
-
@thread_pool << client
|
566
|
-
end
|
567
|
-
rescue SystemCallError
|
568
|
-
end
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
|
-
@events.debug "Drained #{count} additional connections."
|
573
|
-
end
|
574
|
-
|
575
562
|
if @status != :restart
|
576
563
|
@binder.close
|
577
564
|
end
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -13,7 +13,7 @@ module Puma
|
|
13
13
|
# a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in a `@todo` array.
|
14
14
|
#
|
15
15
|
# Each thread in the pool has an internal loop where it pulls a request from the `@todo` array
|
16
|
-
# and
|
16
|
+
# and processes it.
|
17
17
|
class ThreadPool
|
18
18
|
class ForceShutdown < RuntimeError
|
19
19
|
end
|
@@ -29,7 +29,7 @@ module Puma
|
|
29
29
|
# The block passed is the work that will be performed in each
|
30
30
|
# thread.
|
31
31
|
#
|
32
|
-
def initialize(min, max, *extra, &block)
|
32
|
+
def initialize(name, min, max, *extra, &block)
|
33
33
|
@not_empty = ConditionVariable.new
|
34
34
|
@not_full = ConditionVariable.new
|
35
35
|
@mutex = Mutex.new
|
@@ -39,6 +39,7 @@ module Puma
|
|
39
39
|
@spawned = 0
|
40
40
|
@waiting = 0
|
41
41
|
|
42
|
+
@name = name
|
42
43
|
@min = Integer(min)
|
43
44
|
@max = Integer(max)
|
44
45
|
@block = block
|
@@ -101,7 +102,7 @@ module Puma
|
|
101
102
|
@spawned += 1
|
102
103
|
|
103
104
|
th = Thread.new(@spawned) do |spawned|
|
104
|
-
Puma.set_thread_name 'threadpool %03i' % spawned
|
105
|
+
Puma.set_thread_name '%s threadpool %03i' % [@name, spawned]
|
105
106
|
todo = @todo
|
106
107
|
block = @block
|
107
108
|
mutex = @mutex
|
@@ -119,6 +120,7 @@ module Puma
|
|
119
120
|
@trim_requested -= 1
|
120
121
|
@spawned -= 1
|
121
122
|
@workers.delete th
|
123
|
+
not_full.signal
|
122
124
|
Thread.exit
|
123
125
|
end
|
124
126
|
|
@@ -220,7 +222,7 @@ module Puma
|
|
220
222
|
# then the `@todo` array would stay the same size as the reactor works
|
221
223
|
# to try to buffer the request. In that scenario the next call to this
|
222
224
|
# method would not block and another request would be added into the reactor
|
223
|
-
# by the server. This would continue until a fully
|
225
|
+
# by the server. This would continue until a fully buffered request
|
224
226
|
# makes it through the reactor and can then be processed by the thread pool.
|
225
227
|
def wait_until_not_full
|
226
228
|
with_mutex do
|
@@ -240,11 +242,12 @@ module Puma
|
|
240
242
|
|
241
243
|
# @version 5.0.0
|
242
244
|
def wait_for_less_busy_worker(delay_s)
|
245
|
+
return unless delay_s && delay_s > 0
|
246
|
+
|
243
247
|
# Ruby MRI does GVL, this can result
|
244
248
|
# in processing contention when multiple threads
|
245
249
|
# (requests) are running concurrently
|
246
250
|
return unless Puma.mri?
|
247
|
-
return unless delay_s > 0
|
248
251
|
|
249
252
|
with_mutex do
|
250
253
|
return if @shutdown
|
@@ -317,12 +320,12 @@ module Puma
|
|
317
320
|
end
|
318
321
|
|
319
322
|
def auto_trim!(timeout=30)
|
320
|
-
@auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
|
323
|
+
@auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
|
321
324
|
@auto_trim.start!
|
322
325
|
end
|
323
326
|
|
324
327
|
def auto_reap!(timeout=5)
|
325
|
-
@reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
|
328
|
+
@reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
|
326
329
|
@reaper.start!
|
327
330
|
end
|
328
331
|
|
data/lib/puma/util.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.4.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -17,8 +17,8 @@ dependencies:
|
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: '2.0'
|
19
19
|
name: nio4r
|
20
|
-
type: :runtime
|
21
20
|
prerelease: false
|
21
|
+
type: :runtime
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
@@ -93,7 +93,7 @@ files:
|
|
93
93
|
- lib/puma/events.rb
|
94
94
|
- lib/puma/io_buffer.rb
|
95
95
|
- lib/puma/jruby_restart.rb
|
96
|
-
- lib/puma/
|
96
|
+
- lib/puma/json_serialization.rb
|
97
97
|
- lib/puma/launcher.rb
|
98
98
|
- lib/puma/minissl.rb
|
99
99
|
- lib/puma/minissl/context_builder.rb
|
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
140
|
- !ruby/object:Gem::Version
|
141
141
|
version: '0'
|
142
142
|
requirements: []
|
143
|
-
rubygems_version: 3.
|
143
|
+
rubygems_version: 3.1.6
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
146
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|