puma 6.6.0 → 7.0.3
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 +131 -5
- data/README.md +18 -31
- data/docs/fork_worker.md +5 -5
- data/docs/kubernetes.md +6 -4
- data/docs/restart.md +2 -2
- data/docs/signals.md +11 -11
- data/docs/stats.md +2 -1
- data/docs/systemd.md +1 -1
- data/ext/puma_http11/extconf.rb +2 -17
- data/ext/puma_http11/mini_ssl.c +0 -5
- data/ext/puma_http11/org/jruby/puma/Http11.java +1 -1
- data/lib/puma/binder.rb +10 -8
- data/lib/puma/cli.rb +3 -5
- data/lib/puma/client.rb +74 -36
- data/lib/puma/cluster/worker.rb +9 -10
- data/lib/puma/cluster/worker_handle.rb +36 -5
- data/lib/puma/cluster.rb +35 -22
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +88 -43
- data/lib/puma/const.rb +9 -10
- data/lib/puma/control_cli.rb +6 -2
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +110 -90
- data/lib/puma/error_logger.rb +3 -1
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +28 -29
- data/lib/puma/minissl.rb +0 -1
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -4
- data/lib/puma/request.rb +45 -32
- data/lib/puma/runner.rb +8 -17
- data/lib/puma/server.rb +80 -48
- data/lib/puma/single.rb +5 -2
- data/lib/puma/thread_pool.rb +37 -81
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +2 -2
- data/tools/Dockerfile +3 -1
- metadata +4 -4
data/lib/puma/thread_pool.rb
CHANGED
@@ -25,6 +25,8 @@ module Puma
|
|
25
25
|
# up its work before leaving the thread to die on the vine.
|
26
26
|
SHUTDOWN_GRACE_TIME = 5 # seconds
|
27
27
|
|
28
|
+
attr_reader :out_of_band_running
|
29
|
+
|
28
30
|
# Maintain a minimum of +min+ and maximum of +max+ threads
|
29
31
|
# in the pool.
|
30
32
|
#
|
@@ -35,9 +37,9 @@ module Puma
|
|
35
37
|
@not_empty = ConditionVariable.new
|
36
38
|
@not_full = ConditionVariable.new
|
37
39
|
@mutex = Mutex.new
|
40
|
+
@todo = Queue.new
|
38
41
|
|
39
|
-
@
|
40
|
-
|
42
|
+
@backlog_max = 0
|
41
43
|
@spawned = 0
|
42
44
|
@waiting = 0
|
43
45
|
|
@@ -50,7 +52,8 @@ module Puma
|
|
50
52
|
@shutdown_grace_time = Float(options[:pool_shutdown_grace_time] || SHUTDOWN_GRACE_TIME)
|
51
53
|
@block = block
|
52
54
|
@out_of_band = options[:out_of_band]
|
53
|
-
@
|
55
|
+
@out_of_band_running = false
|
56
|
+
@out_of_band_condvar = ConditionVariable.new
|
54
57
|
@before_thread_start = options[:before_thread_start]
|
55
58
|
@before_thread_exit = options[:before_thread_exit]
|
56
59
|
@reaping_time = options[:reaping_time]
|
@@ -79,30 +82,37 @@ module Puma
|
|
79
82
|
|
80
83
|
attr_reader :spawned, :trim_requested, :waiting
|
81
84
|
|
82
|
-
def self.clean_thread_locals
|
83
|
-
Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
|
84
|
-
Thread.current[key] = nil unless key == :__recursive_key__
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
85
|
# generate stats hash so as not to perform multiple locks
|
89
86
|
# @return [Hash] hash containing stat info from ThreadPool
|
90
87
|
def stats
|
91
88
|
with_mutex do
|
89
|
+
temp = @backlog_max
|
90
|
+
@backlog_max = 0
|
92
91
|
{ backlog: @todo.size,
|
93
92
|
running: @spawned,
|
94
93
|
pool_capacity: @waiting + (@max - @spawned),
|
95
|
-
busy_threads: @spawned - @waiting + @todo.size
|
94
|
+
busy_threads: @spawned - @waiting + @todo.size,
|
95
|
+
backlog_max: temp
|
96
96
|
}
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
def reset_max
|
101
|
+
with_mutex { @backlog_max = 0 }
|
102
|
+
end
|
103
|
+
|
100
104
|
# How many objects have yet to be processed by the pool?
|
101
105
|
#
|
102
106
|
def backlog
|
103
107
|
with_mutex { @todo.size }
|
104
108
|
end
|
105
109
|
|
110
|
+
# The maximum size of the backlog
|
111
|
+
#
|
112
|
+
def backlog_max
|
113
|
+
with_mutex { @backlog_max }
|
114
|
+
end
|
115
|
+
|
106
116
|
# @!attribute [r] pool_capacity
|
107
117
|
def pool_capacity
|
108
118
|
waiting + (@max - spawned)
|
@@ -159,10 +169,6 @@ module Puma
|
|
159
169
|
work = todo.shift
|
160
170
|
end
|
161
171
|
|
162
|
-
if @clean_thread_locals
|
163
|
-
ThreadPool.clean_thread_locals
|
164
|
-
end
|
165
|
-
|
166
172
|
begin
|
167
173
|
@out_of_band_pending = true if block.call(work)
|
168
174
|
rescue Exception => e
|
@@ -183,7 +189,7 @@ module Puma
|
|
183
189
|
|
184
190
|
@before_thread_start.each do |b|
|
185
191
|
begin
|
186
|
-
b.call
|
192
|
+
b[:block].call
|
187
193
|
rescue Exception => e
|
188
194
|
STDERR.puts "WARNING before_thread_start hook failed with exception (#{e.class}) #{e.message}"
|
189
195
|
end
|
@@ -198,7 +204,7 @@ module Puma
|
|
198
204
|
|
199
205
|
@before_thread_exit.each do |b|
|
200
206
|
begin
|
201
|
-
b.call
|
207
|
+
b[:block].call
|
202
208
|
rescue Exception => e
|
203
209
|
STDERR.puts "WARNING before_thread_exit hook failed with exception (#{e.class}) #{e.message}"
|
204
210
|
end
|
@@ -214,16 +220,27 @@ module Puma
|
|
214
220
|
|
215
221
|
# we execute on idle hook when all threads are free
|
216
222
|
return false unless @spawned == @waiting
|
217
|
-
|
218
|
-
@out_of_band.each
|
223
|
+
@out_of_band_running = true
|
224
|
+
@out_of_band.each { |b| b[:block].call }
|
219
225
|
true
|
220
226
|
rescue Exception => e
|
221
227
|
STDERR.puts "Exception calling out_of_band_hook: #{e.message} (#{e.class})"
|
222
228
|
true
|
229
|
+
ensure
|
230
|
+
@out_of_band_running = false
|
231
|
+
@out_of_band_condvar.broadcast
|
223
232
|
end
|
224
233
|
|
225
234
|
private :trigger_out_of_band_hook
|
226
235
|
|
236
|
+
def wait_while_out_of_band_running
|
237
|
+
return unless @out_of_band_running
|
238
|
+
|
239
|
+
with_mutex do
|
240
|
+
@out_of_band_condvar.wait(@mutex) while @out_of_band_running
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
227
244
|
# @version 5.0.0
|
228
245
|
def with_mutex(&block)
|
229
246
|
@mutex.owned? ?
|
@@ -239,6 +256,8 @@ module Puma
|
|
239
256
|
end
|
240
257
|
|
241
258
|
@todo << work
|
259
|
+
t = @todo.size
|
260
|
+
@backlog_max = t if t > @backlog_max
|
242
261
|
|
243
262
|
if @waiting < @todo.size and @spawned < @max
|
244
263
|
spawn_thread
|
@@ -248,69 +267,6 @@ module Puma
|
|
248
267
|
end
|
249
268
|
end
|
250
269
|
|
251
|
-
# This method is used by `Puma::Server` to let the server know when
|
252
|
-
# the thread pool can pull more requests from the socket and
|
253
|
-
# pass to the reactor.
|
254
|
-
#
|
255
|
-
# The general idea is that the thread pool can only work on a fixed
|
256
|
-
# number of requests at the same time. If it is already processing that
|
257
|
-
# number of requests then it is at capacity. If another Puma process has
|
258
|
-
# spare capacity, then the request can be left on the socket so the other
|
259
|
-
# worker can pick it up and process it.
|
260
|
-
#
|
261
|
-
# For example: if there are 5 threads, but only 4 working on
|
262
|
-
# requests, this method will not wait and the `Puma::Server`
|
263
|
-
# can pull a request right away.
|
264
|
-
#
|
265
|
-
# If there are 5 threads and all 5 of them are busy, then it will
|
266
|
-
# pause here, and wait until the `not_full` condition variable is
|
267
|
-
# signaled, usually this indicates that a request has been processed.
|
268
|
-
#
|
269
|
-
# It's important to note that even though the server might accept another
|
270
|
-
# request, it might not be added to the `@todo` array right away.
|
271
|
-
# For example if a slow client has only sent a header, but not a body
|
272
|
-
# then the `@todo` array would stay the same size as the reactor works
|
273
|
-
# to try to buffer the request. In that scenario the next call to this
|
274
|
-
# method would not block and another request would be added into the reactor
|
275
|
-
# by the server. This would continue until a fully buffered request
|
276
|
-
# makes it through the reactor and can then be processed by the thread pool.
|
277
|
-
def wait_until_not_full
|
278
|
-
with_mutex do
|
279
|
-
while true
|
280
|
-
return if @shutdown
|
281
|
-
|
282
|
-
# If we can still spin up new threads and there
|
283
|
-
# is work queued that cannot be handled by waiting
|
284
|
-
# threads, then accept more work until we would
|
285
|
-
# spin up the max number of threads.
|
286
|
-
return if busy_threads < @max
|
287
|
-
|
288
|
-
@not_full.wait @mutex
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
# @version 5.0.0
|
294
|
-
def wait_for_less_busy_worker(delay_s)
|
295
|
-
return unless delay_s && delay_s > 0
|
296
|
-
|
297
|
-
# Ruby MRI does GVL, this can result
|
298
|
-
# in processing contention when multiple threads
|
299
|
-
# (requests) are running concurrently
|
300
|
-
return unless Puma.mri?
|
301
|
-
|
302
|
-
with_mutex do
|
303
|
-
return if @shutdown
|
304
|
-
|
305
|
-
# do not delay, if we are not busy
|
306
|
-
return unless busy_threads > 0
|
307
|
-
|
308
|
-
# this will be signaled once a request finishes,
|
309
|
-
# which can happen earlier than delay
|
310
|
-
@not_full.wait @mutex, delay_s
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
270
|
# If there are any free threads in the pool, tell one to go ahead
|
315
271
|
# and exit. If +force+ is true, then a trim request is requested
|
316
272
|
# even if all threads are being utilized.
|
data/lib/puma/util.rb
CHANGED
@@ -10,13 +10,6 @@ module Puma
|
|
10
10
|
IO.pipe
|
11
11
|
end
|
12
12
|
|
13
|
-
# An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
|
14
|
-
# which currently affects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
|
15
|
-
# Additional context: https://github.com/puma/puma/pull/1345
|
16
|
-
def purge_interrupt_queue
|
17
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
18
|
-
end
|
19
|
-
|
20
13
|
# Escapes and unescapes a URI escaped string with
|
21
14
|
# +encoding+. +encoding+ will be the target encoding of the string
|
22
15
|
# returned, and it defaults to UTF-8
|
data/lib/puma.rb
CHANGED
@@ -75,4 +75,14 @@ module Puma
|
|
75
75
|
def self.set_thread_name(name)
|
76
76
|
Thread.current.name = "puma #{name}"
|
77
77
|
end
|
78
|
+
|
79
|
+
# Shows deprecated warning for renamed methods.
|
80
|
+
# @example
|
81
|
+
# Puma.deprecate_method_change :on_booted, __callee__, __method__
|
82
|
+
#
|
83
|
+
def self.deprecate_method_change(method_old, method_caller, method_new)
|
84
|
+
if method_old == method_caller
|
85
|
+
warn "Use '#{method_new}', '#{method_caller}' is deprecated and will be removed in v8"
|
86
|
+
end
|
87
|
+
end
|
78
88
|
end
|
data/lib/rack/handler/puma.rb
CHANGED
@@ -32,7 +32,7 @@ module Puma
|
|
32
32
|
|
33
33
|
@events = options[:events] || ::Puma::Events.new
|
34
34
|
|
35
|
-
conf = ::Puma::Configuration.new(options, default_options.merge({events: @events})) do |user_config, file_config, default_config|
|
35
|
+
conf = ::Puma::Configuration.new(options, default_options.merge({ events: @events })) do |user_config, file_config, default_config|
|
36
36
|
if options.delete(:Verbose)
|
37
37
|
begin
|
38
38
|
require 'rack/commonlogger' # Rack 1.x
|
@@ -72,7 +72,7 @@ module Puma
|
|
72
72
|
|
73
73
|
log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio
|
74
74
|
|
75
|
-
launcher = ::Puma::Launcher.new(conf, :
|
75
|
+
launcher = ::Puma::Launcher.new(conf, log_writer: log_writer, events: @events)
|
76
76
|
|
77
77
|
yield launcher if block_given?
|
78
78
|
begin
|
data/tools/Dockerfile
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
FROM ruby:3.2
|
4
4
|
|
5
|
+
RUN apt-get update && apt-get install -y ragel
|
6
|
+
|
5
7
|
# throw errors if Gemfile has been modified since Gemfile.lock
|
6
8
|
RUN bundle config --global frozen 1
|
7
9
|
|
@@ -13,4 +15,4 @@ RUN bundle install
|
|
13
15
|
RUN bundle exec rake compile
|
14
16
|
|
15
17
|
EXPOSE 9292
|
16
|
-
CMD bundle exec bin/puma test/rackup/hello.ru
|
18
|
+
CMD ["bundle", "exec", "bin/puma", "test/rackup/hello.ru"]
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 7.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: nio4r
|
@@ -138,14 +138,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
138
|
requirements:
|
139
139
|
- - ">="
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version: '
|
141
|
+
version: '3.0'
|
142
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
143
|
requirements:
|
144
144
|
- - ">="
|
145
145
|
- !ruby/object:Gem::Version
|
146
146
|
version: '0'
|
147
147
|
requirements: []
|
148
|
-
rubygems_version: 3.6.
|
148
|
+
rubygems_version: 3.6.9
|
149
149
|
specification_version: 4
|
150
150
|
summary: A Ruby/Rack web server built for parallelism.
|
151
151
|
test_files: []
|