puma 5.2.0 → 5.3.2
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.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +93 -0
- data/README.md +1 -1
- data/docs/architecture.md +22 -18
- data/docs/deployment.md +1 -1
- data/docs/jungle/rc.d/README.md +1 -1
- data/docs/kubernetes.md +1 -1
- data/docs/plugins.md +1 -1
- data/docs/rails_dev_mode.md +29 -0
- data/docs/restart.md +1 -1
- data/docs/stats.md +1 -1
- data/docs/systemd.md +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/lib/puma.rb +34 -8
- data/lib/puma/binder.rb +29 -21
- data/lib/puma/client.rb +7 -4
- data/lib/puma/cluster.rb +40 -8
- data/lib/puma/cluster/worker.rb +8 -1
- data/lib/puma/cluster/worker_handle.rb +4 -0
- data/lib/puma/configuration.rb +5 -1
- data/lib/puma/const.rb +3 -3
- data/lib/puma/control_cli.rb +3 -1
- data/lib/puma/detect.rb +14 -10
- data/lib/puma/dsl.rb +23 -1
- data/lib/puma/error_logger.rb +2 -2
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/null_io.rb +8 -0
- data/lib/puma/queue_close.rb +7 -7
- data/lib/puma/request.rb +23 -7
- data/lib/puma/runner.rb +5 -0
- data/lib/puma/server.rb +34 -50
- data/lib/puma/thread_pool.rb +4 -3
- data/lib/rack/handler/puma.rb +1 -0
- metadata +4 -3
data/lib/puma/runner.rb
CHANGED
@@ -126,6 +126,11 @@ module Puma
|
|
126
126
|
STDERR.puts "=== puma startup: #{Time.now} ==="
|
127
127
|
STDERR.flush unless STDERR.sync
|
128
128
|
end
|
129
|
+
|
130
|
+
if @options[:mutate_stdout_and_stderr_to_sync_on_write]
|
131
|
+
STDOUT.sync = true
|
132
|
+
STDERR.sync = true
|
133
|
+
end
|
129
134
|
end
|
130
135
|
|
131
136
|
def load_and_bind
|
data/lib/puma/server.rb
CHANGED
@@ -120,17 +120,13 @@ module Puma
|
|
120
120
|
# :nodoc:
|
121
121
|
# @version 5.0.0
|
122
122
|
def tcp_cork_supported?
|
123
|
-
|
124
|
-
Socket.const_defined?(:IPPROTO_TCP) &&
|
125
|
-
Socket.const_defined?(:TCP_CORK)
|
123
|
+
Socket.const_defined?(:TCP_CORK) && Socket.const_defined?(:IPPROTO_TCP)
|
126
124
|
end
|
127
125
|
|
128
126
|
# :nodoc:
|
129
127
|
# @version 5.0.0
|
130
128
|
def closed_socket_supported?
|
131
|
-
|
132
|
-
Socket.const_defined?(:IPPROTO_TCP) &&
|
133
|
-
Socket.const_defined?(:TCP_INFO)
|
129
|
+
Socket.const_defined?(:TCP_INFO) && Socket.const_defined?(:IPPROTO_TCP)
|
134
130
|
end
|
135
131
|
private :tcp_cork_supported?
|
136
132
|
private :closed_socket_supported?
|
@@ -138,24 +134,25 @@ module Puma
|
|
138
134
|
|
139
135
|
# On Linux, use TCP_CORK to better control how the TCP stack
|
140
136
|
# packetizes our stream. This improves both latency and throughput.
|
137
|
+
# socket parameter may be an MiniSSL::Socket, so use to_io
|
141
138
|
#
|
142
139
|
if tcp_cork_supported?
|
143
|
-
UNPACK_TCP_STATE_FROM_TCP_INFO = "C".freeze
|
144
|
-
|
145
140
|
# 6 == Socket::IPPROTO_TCP
|
146
141
|
# 3 == TCP_CORK
|
147
142
|
# 1/0 == turn on/off
|
148
143
|
def cork_socket(socket)
|
144
|
+
skt = socket.to_io
|
149
145
|
begin
|
150
|
-
|
146
|
+
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 1) if skt.kind_of? TCPSocket
|
151
147
|
rescue IOError, SystemCallError
|
152
148
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
153
149
|
end
|
154
150
|
end
|
155
151
|
|
156
152
|
def uncork_socket(socket)
|
153
|
+
skt = socket.to_io
|
157
154
|
begin
|
158
|
-
|
155
|
+
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 0) if skt.kind_of? TCPSocket
|
159
156
|
rescue IOError, SystemCallError
|
160
157
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
161
158
|
end
|
@@ -169,12 +166,14 @@ module Puma
|
|
169
166
|
end
|
170
167
|
|
171
168
|
if closed_socket_supported?
|
169
|
+
UNPACK_TCP_STATE_FROM_TCP_INFO = "C".freeze
|
170
|
+
|
172
171
|
def closed_socket?(socket)
|
173
|
-
|
174
|
-
return false unless @precheck_closing
|
172
|
+
skt = socket.to_io
|
173
|
+
return false unless skt.kind_of?(TCPSocket) && @precheck_closing
|
175
174
|
|
176
175
|
begin
|
177
|
-
tcp_info =
|
176
|
+
tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
|
178
177
|
rescue IOError, SystemCallError
|
179
178
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
180
179
|
@precheck_closing = false
|
@@ -296,6 +295,9 @@ module Puma
|
|
296
295
|
@thread_pool << client
|
297
296
|
elsif shutdown || client.timeout == 0
|
298
297
|
client.timeout!
|
298
|
+
else
|
299
|
+
client.set_timeout(@first_data_timeout)
|
300
|
+
false
|
299
301
|
end
|
300
302
|
rescue StandardError => e
|
301
303
|
client_error(e, client)
|
@@ -309,6 +311,7 @@ module Puma
|
|
309
311
|
sockets = [check] + @binder.ios
|
310
312
|
pool = @thread_pool
|
311
313
|
queue_requests = @queue_requests
|
314
|
+
drain = @options[:drain_on_shutdown] ? 0 : nil
|
312
315
|
|
313
316
|
remote_addr_value = nil
|
314
317
|
remote_addr_header = nil
|
@@ -320,23 +323,25 @@ module Puma
|
|
320
323
|
remote_addr_header = @options[:remote_address_header]
|
321
324
|
end
|
322
325
|
|
323
|
-
while @status == :run
|
326
|
+
while @status == :run || (drain && shutting_down?)
|
324
327
|
begin
|
325
|
-
ios = IO.select sockets
|
328
|
+
ios = IO.select sockets, nil, nil, (shutting_down? ? 0 : nil)
|
329
|
+
break unless ios
|
326
330
|
ios.first.each do |sock|
|
327
331
|
if sock == check
|
328
332
|
break if handle_check
|
329
333
|
else
|
330
334
|
pool.wait_until_not_full
|
331
|
-
pool.wait_for_less_busy_worker(
|
332
|
-
@options[:wait_for_less_busy_worker].to_f)
|
335
|
+
pool.wait_for_less_busy_worker(@options[:wait_for_less_busy_worker])
|
333
336
|
|
334
337
|
io = begin
|
335
338
|
sock.accept_nonblock
|
336
339
|
rescue IO::WaitReadable
|
337
340
|
next
|
338
341
|
end
|
342
|
+
drain += 1 if shutting_down?
|
339
343
|
client = Client.new io, @binder.env(sock)
|
344
|
+
client.listener = sock
|
340
345
|
if remote_addr_value
|
341
346
|
client.peerip = remote_addr_value
|
342
347
|
elsif remote_addr_header
|
@@ -350,6 +355,7 @@ module Puma
|
|
350
355
|
end
|
351
356
|
end
|
352
357
|
|
358
|
+
@events.debug "Drained #{drain} additional connections." if drain
|
353
359
|
@events.fire :state, @status
|
354
360
|
|
355
361
|
if queue_requests
|
@@ -429,7 +435,7 @@ module Puma
|
|
429
435
|
|
430
436
|
while true
|
431
437
|
@requests_count += 1
|
432
|
-
case handle_request(client, buffer)
|
438
|
+
case handle_request(client, buffer, requests + 1)
|
433
439
|
when false
|
434
440
|
break
|
435
441
|
when :async
|
@@ -442,18 +448,17 @@ module Puma
|
|
442
448
|
|
443
449
|
requests += 1
|
444
450
|
|
445
|
-
|
451
|
+
# As an optimization, try to read the next request from the
|
452
|
+
# socket for a short time before returning to the reactor.
|
453
|
+
fast_check = @status == :run
|
446
454
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
# one once every max_fast_inline requests.
|
452
|
-
check_for_more_data = false
|
453
|
-
end
|
455
|
+
# Always pass the client back to the reactor after a reasonable
|
456
|
+
# number of inline requests if there are other requests pending.
|
457
|
+
fast_check = false if requests >= @max_fast_inline &&
|
458
|
+
@thread_pool.backlog > 0
|
454
459
|
|
455
460
|
next_request_ready = with_force_shutdown(client) do
|
456
|
-
client.reset(
|
461
|
+
client.reset(fast_check)
|
457
462
|
end
|
458
463
|
|
459
464
|
unless next_request_ready
|
@@ -527,7 +532,8 @@ module Puma
|
|
527
532
|
end
|
528
533
|
|
529
534
|
if @leak_stack_on_error
|
530
|
-
|
535
|
+
backtrace = e.backtrace.nil? ? '<no backtrace available>' : e.backtrace.join("\n")
|
536
|
+
[status, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{backtrace}"]]
|
531
537
|
else
|
532
538
|
[status, {}, ["An unhandled lowlevel error occurred. The application logs may have details.\n"]]
|
533
539
|
end
|
@@ -551,28 +557,6 @@ module Puma
|
|
551
557
|
$stdout.syswrite "#{pid}: === End thread backtrace dump ===\n"
|
552
558
|
end
|
553
559
|
|
554
|
-
if @options[:drain_on_shutdown]
|
555
|
-
count = 0
|
556
|
-
|
557
|
-
while true
|
558
|
-
ios = IO.select @binder.ios, nil, nil, 0
|
559
|
-
break unless ios
|
560
|
-
|
561
|
-
ios.first.each do |sock|
|
562
|
-
begin
|
563
|
-
if io = sock.accept_nonblock
|
564
|
-
count += 1
|
565
|
-
client = Client.new io, @binder.env(sock)
|
566
|
-
@thread_pool << client
|
567
|
-
end
|
568
|
-
rescue SystemCallError
|
569
|
-
end
|
570
|
-
end
|
571
|
-
end
|
572
|
-
|
573
|
-
@events.debug "Drained #{count} additional connections."
|
574
|
-
end
|
575
|
-
|
576
560
|
if @status != :restart
|
577
561
|
@binder.close
|
578
562
|
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
|
@@ -220,7 +220,7 @@ module Puma
|
|
220
220
|
# then the `@todo` array would stay the same size as the reactor works
|
221
221
|
# to try to buffer the request. In that scenario the next call to this
|
222
222
|
# method would not block and another request would be added into the reactor
|
223
|
-
# by the server. This would continue until a fully
|
223
|
+
# by the server. This would continue until a fully buffered request
|
224
224
|
# makes it through the reactor and can then be processed by the thread pool.
|
225
225
|
def wait_until_not_full
|
226
226
|
with_mutex do
|
@@ -240,11 +240,12 @@ module Puma
|
|
240
240
|
|
241
241
|
# @version 5.0.0
|
242
242
|
def wait_for_less_busy_worker(delay_s)
|
243
|
+
return unless delay_s && delay_s > 0
|
244
|
+
|
243
245
|
# Ruby MRI does GVL, this can result
|
244
246
|
# in processing contention when multiple threads
|
245
247
|
# (requests) are running concurrently
|
246
248
|
return unless Puma.mri?
|
247
|
-
return unless delay_s > 0
|
248
249
|
|
249
250
|
with_mutex do
|
250
251
|
return if @shutdown
|
data/lib/rack/handler/puma.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.2
|
4
|
+
version: 5.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- docs/kubernetes.md
|
58
58
|
- docs/nginx.md
|
59
59
|
- docs/plugins.md
|
60
|
+
- docs/rails_dev_mode.md
|
60
61
|
- docs/restart.md
|
61
62
|
- docs/signals.md
|
62
63
|
- docs/stats.md
|
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
140
|
- !ruby/object:Gem::Version
|
140
141
|
version: '0'
|
141
142
|
requirements: []
|
142
|
-
rubygems_version: 3.2.
|
143
|
+
rubygems_version: 3.2.3
|
143
144
|
signing_key:
|
144
145
|
specification_version: 4
|
145
146
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|