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.

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
- return false unless socket.kind_of? TCPSocket
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 = socket.getsockopt(Socket::IPPROTO_TCP, Socket::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
- return false
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
- check_for_more_data = @status == :run
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
- if requests >= @max_fast_inline
447
- # This will mean that reset will only try to use the data it already
448
- # has buffered and won't try to read more data. What this means is that
449
- # every client, independent of their request speed, gets treated like a slow
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(check_for_more_data)
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
- [status, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{e.backtrace.join("\n")}"]]
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
@@ -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 proceses it.
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 bufferend request
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
@@ -61,7 +61,7 @@ module Puma
61
61
  end
62
62
  end
63
63
 
64
- return params
64
+ params
65
65
  end
66
66
 
67
67
  # A case-insensitive Hash that preserves the original case of a
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.2
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-03-02 00:00:00.000000000 Z
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/json.rb
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.0.6
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