puma 6.6.0 → 8.0.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +309 -5
  3. data/README.md +41 -42
  4. data/docs/5.0-Upgrade.md +98 -0
  5. data/docs/6.0-Upgrade.md +56 -0
  6. data/docs/7.0-Upgrade.md +52 -0
  7. data/docs/8.0-Upgrade.md +100 -0
  8. data/docs/deployment.md +58 -23
  9. data/docs/fork_worker.md +5 -5
  10. data/docs/grpc.md +62 -0
  11. data/docs/images/favicon.svg +1 -0
  12. data/docs/images/running-puma.svg +1 -0
  13. data/docs/images/standard-logo.svg +1 -0
  14. data/docs/jungle/README.md +1 -1
  15. data/docs/kubernetes.md +11 -16
  16. data/docs/plugins.md +2 -2
  17. data/docs/restart.md +2 -2
  18. data/docs/signals.md +21 -21
  19. data/docs/stats.md +4 -3
  20. data/docs/systemd.md +4 -4
  21. data/ext/puma_http11/extconf.rb +2 -17
  22. data/ext/puma_http11/http11_parser.java.rl +51 -65
  23. data/ext/puma_http11/mini_ssl.c +18 -8
  24. data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
  25. data/ext/puma_http11/org/jruby/puma/Http11.java +174 -102
  26. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +71 -85
  27. data/ext/puma_http11/puma_http11.c +122 -118
  28. data/lib/puma/app/status.rb +10 -2
  29. data/lib/puma/binder.rb +12 -10
  30. data/lib/puma/cli.rb +4 -6
  31. data/lib/puma/client.rb +205 -131
  32. data/lib/puma/client_env.rb +171 -0
  33. data/lib/puma/cluster/worker.rb +17 -17
  34. data/lib/puma/cluster/worker_handle.rb +38 -7
  35. data/lib/puma/cluster.rb +44 -30
  36. data/lib/puma/cluster_accept_loop_delay.rb +91 -0
  37. data/lib/puma/commonlogger.rb +3 -3
  38. data/lib/puma/configuration.rb +173 -58
  39. data/lib/puma/const.rb +11 -11
  40. data/lib/puma/control_cli.rb +7 -3
  41. data/lib/puma/detect.rb +13 -0
  42. data/lib/puma/dsl.rb +225 -108
  43. data/lib/puma/error_logger.rb +3 -1
  44. data/lib/puma/events.rb +25 -10
  45. data/lib/puma/io_buffer.rb +8 -4
  46. data/lib/puma/launcher/bundle_pruner.rb +3 -5
  47. data/lib/puma/launcher.rb +57 -53
  48. data/lib/puma/log_writer.rb +8 -2
  49. data/lib/puma/minissl.rb +0 -1
  50. data/lib/puma/plugin/systemd.rb +3 -3
  51. data/lib/puma/rack/urlmap.rb +1 -1
  52. data/lib/puma/reactor.rb +19 -13
  53. data/lib/puma/{request.rb → response.rb} +56 -212
  54. data/lib/puma/runner.rb +9 -18
  55. data/lib/puma/server.rb +182 -97
  56. data/lib/puma/server_plugin_control.rb +32 -0
  57. data/lib/puma/single.rb +7 -4
  58. data/lib/puma/state_file.rb +3 -2
  59. data/lib/puma/thread_pool.rb +170 -99
  60. data/lib/puma/util.rb +0 -7
  61. data/lib/puma.rb +10 -0
  62. data/lib/rack/handler/puma.rb +3 -3
  63. data/tools/Dockerfile +15 -5
  64. metadata +19 -7
  65. data/ext/puma_http11/ext_help.h +0 -15
@@ -3,8 +3,13 @@
3
3
  require 'thread'
4
4
 
5
5
  require_relative 'io_buffer'
6
+ require_relative 'server_plugin_control'
6
7
 
7
8
  module Puma
9
+
10
+ # Add `Thread#puma_server` and `Thread#puma_server=`
11
+ Thread.attr_accessor(:puma_server)
12
+
8
13
  # Internal Docs for A simple thread pool management object.
9
14
  #
10
15
  # Each Puma "worker" has a thread pool to process requests.
@@ -20,37 +25,90 @@ module Puma
20
25
  class ForceShutdown < RuntimeError
21
26
  end
22
27
 
28
+ class ProcessorThread
29
+ attr_accessor :thread
30
+ attr_writer :marked_as_io_thread
31
+
32
+ def initialize(pool)
33
+ @pool = pool
34
+ @thread = nil
35
+ @marked_as_io_thread = false
36
+ end
37
+
38
+ def mark_as_io_thread!
39
+ unless @marked_as_io_thread
40
+ @marked_as_io_thread = true
41
+
42
+ # Immediately signal the pool that it can spawn a new thread
43
+ # if there's some work in the queue.
44
+ @pool.spawn_thread_if_needed
45
+ end
46
+ end
47
+
48
+ def marked_as_io_thread?
49
+ @marked_as_io_thread
50
+ end
51
+
52
+ def alive?
53
+ @thread&.alive?
54
+ end
55
+
56
+ def join(...)
57
+ @thread.join(...)
58
+ end
59
+
60
+ def kill(...)
61
+ @thread.kill(...)
62
+ end
63
+
64
+ def [](key)
65
+ @thread[key]
66
+ end
67
+
68
+ def raise(...)
69
+ @thread.raise(...)
70
+ end
71
+ end
72
+
23
73
  # How long, after raising the ForceShutdown of a thread during
24
74
  # forced shutdown mode, to wait for the thread to try and finish
25
75
  # up its work before leaving the thread to die on the vine.
26
76
  SHUTDOWN_GRACE_TIME = 5 # seconds
27
77
 
78
+ attr_reader :out_of_band_running
79
+
28
80
  # Maintain a minimum of +min+ and maximum of +max+ threads
29
81
  # in the pool.
30
82
  #
31
83
  # The block passed is the work that will be performed in each
32
84
  # thread.
33
85
  #
34
- def initialize(name, options = {}, &block)
86
+ def initialize(name, options = {}, server: nil, &block)
87
+ @server = server
88
+
35
89
  @not_empty = ConditionVariable.new
36
90
  @not_full = ConditionVariable.new
37
91
  @mutex = Mutex.new
92
+ @todo = Queue.new
38
93
 
39
- @todo = []
40
-
94
+ @backlog_max = 0
41
95
  @spawned = 0
42
96
  @waiting = 0
43
97
 
44
98
  @name = name
45
99
  @min = Integer(options[:min_threads])
46
100
  @max = Integer(options[:max_threads])
101
+ @max_io_threads = Integer(options[:max_io_threads] || 0)
102
+
47
103
  # Not an 'exposed' option, options[:pool_shutdown_grace_time] is used in CI
48
104
  # to shorten @shutdown_grace_time from SHUTDOWN_GRACE_TIME. Parallel CI
49
105
  # makes stubbing constants difficult.
50
106
  @shutdown_grace_time = Float(options[:pool_shutdown_grace_time] || SHUTDOWN_GRACE_TIME)
107
+ @shutdown_debug = options[:shutdown_debug]
51
108
  @block = block
52
109
  @out_of_band = options[:out_of_band]
53
- @clean_thread_locals = options[:clean_thread_locals]
110
+ @out_of_band_running = false
111
+ @out_of_band_condvar = ConditionVariable.new
54
112
  @before_thread_start = options[:before_thread_start]
55
113
  @before_thread_exit = options[:before_thread_exit]
56
114
  @reaping_time = options[:reaping_time]
@@ -61,7 +119,7 @@ module Puma
61
119
  @trim_requested = 0
62
120
  @out_of_band_pending = false
63
121
 
64
- @workers = []
122
+ @processors = []
65
123
 
66
124
  @auto_trim = nil
67
125
  @reaper = nil
@@ -78,34 +136,43 @@ module Puma
78
136
  end
79
137
 
80
138
  attr_reader :spawned, :trim_requested, :waiting
81
-
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
139
+ attr_accessor :min, :max
87
140
 
88
141
  # generate stats hash so as not to perform multiple locks
89
142
  # @return [Hash] hash containing stat info from ThreadPool
90
143
  def stats
91
144
  with_mutex do
145
+ temp = @backlog_max
146
+ @backlog_max = 0
92
147
  { backlog: @todo.size,
93
148
  running: @spawned,
94
- pool_capacity: @waiting + (@max - @spawned),
95
- busy_threads: @spawned - @waiting + @todo.size
149
+ pool_capacity: pool_capacity,
150
+ busy_threads: @spawned - @waiting + @todo.size,
151
+ io_threads: @processors.count(&:marked_as_io_thread?),
152
+ backlog_max: temp
96
153
  }
97
154
  end
98
155
  end
99
156
 
157
+ def reset_max
158
+ with_mutex { @backlog_max = 0 }
159
+ end
160
+
100
161
  # How many objects have yet to be processed by the pool?
101
162
  #
102
163
  def backlog
103
164
  with_mutex { @todo.size }
104
165
  end
105
166
 
167
+ # The maximum size of the backlog
168
+ #
169
+ def backlog_max
170
+ with_mutex { @backlog_max }
171
+ end
172
+
106
173
  # @!attribute [r] pool_capacity
107
174
  def pool_capacity
108
- waiting + (@max - spawned)
175
+ (waiting + (@max - spawned)).clamp(0, Float::INFINITY)
109
176
  end
110
177
 
111
178
  # @!attribute [r] busy_threads
@@ -122,8 +189,12 @@ module Puma
122
189
  @spawned += 1
123
190
 
124
191
  trigger_before_thread_start_hooks
125
- th = Thread.new(@spawned) do |spawned|
192
+ processor = ProcessorThread.new(self)
193
+ processor.thread = Thread.new(processor, @spawned) do |processor, spawned|
126
194
  Puma.set_thread_name '%s tp %03i' % [@name, spawned]
195
+ # Advertise server into the thread
196
+ Thread.current.puma_server = @server
197
+
127
198
  todo = @todo
128
199
  block = @block
129
200
  mutex = @mutex
@@ -134,11 +205,23 @@ module Puma
134
205
  work = nil
135
206
 
136
207
  mutex.synchronize do
208
+ if processor.marked_as_io_thread?
209
+ if @processors.count { |t| !t.marked_as_io_thread? } < @max
210
+ # We're not at max processor threads, so the io thread can rejoin the normal population.
211
+ processor.marked_as_io_thread = false
212
+ else
213
+ # We're already at max threads, so we exit the extra io thread.
214
+ @processors.delete(processor)
215
+ trigger_before_thread_exit_hooks
216
+ Thread.exit
217
+ end
218
+ end
219
+
137
220
  while todo.empty?
138
221
  if @trim_requested > 0
139
222
  @trim_requested -= 1
140
223
  @spawned -= 1
141
- @workers.delete th
224
+ @processors.delete(processor)
142
225
  not_full.signal
143
226
  trigger_before_thread_exit_hooks
144
227
  Thread.exit
@@ -159,21 +242,17 @@ module Puma
159
242
  work = todo.shift
160
243
  end
161
244
 
162
- if @clean_thread_locals
163
- ThreadPool.clean_thread_locals
164
- end
165
-
166
245
  begin
167
- @out_of_band_pending = true if block.call(work)
246
+ @out_of_band_pending = true if block.call(processor, work)
168
247
  rescue Exception => e
169
248
  STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
170
249
  end
171
250
  end
172
251
  end
173
252
 
174
- @workers << th
253
+ @processors << processor
175
254
 
176
- th
255
+ processor
177
256
  end
178
257
 
179
258
  private :spawn_thread
@@ -183,7 +262,7 @@ module Puma
183
262
 
184
263
  @before_thread_start.each do |b|
185
264
  begin
186
- b.call
265
+ b[:block].call(ServerPluginControl.new(@server))
187
266
  rescue Exception => e
188
267
  STDERR.puts "WARNING before_thread_start hook failed with exception (#{e.class}) #{e.message}"
189
268
  end
@@ -198,7 +277,7 @@ module Puma
198
277
 
199
278
  @before_thread_exit.each do |b|
200
279
  begin
201
- b.call
280
+ b[:block].call
202
281
  rescue Exception => e
203
282
  STDERR.puts "WARNING before_thread_exit hook failed with exception (#{e.class}) #{e.message}"
204
283
  end
@@ -214,16 +293,27 @@ module Puma
214
293
 
215
294
  # we execute on idle hook when all threads are free
216
295
  return false unless @spawned == @waiting
217
-
218
- @out_of_band.each(&:call)
296
+ @out_of_band_running = true
297
+ @out_of_band.each { |b| b[:block].call }
219
298
  true
220
299
  rescue Exception => e
221
300
  STDERR.puts "Exception calling out_of_band_hook: #{e.message} (#{e.class})"
222
301
  true
302
+ ensure
303
+ @out_of_band_running = false
304
+ @out_of_band_condvar.broadcast
223
305
  end
224
306
 
225
307
  private :trigger_out_of_band_hook
226
308
 
309
+ def wait_while_out_of_band_running
310
+ return unless @out_of_band_running
311
+
312
+ with_mutex do
313
+ @out_of_band_condvar.wait(@mutex) while @out_of_band_running
314
+ end
315
+ end
316
+
227
317
  # @version 5.0.0
228
318
  def with_mutex(&block)
229
319
  @mutex.owned? ?
@@ -231,6 +321,16 @@ module Puma
231
321
  @mutex.synchronize(&block)
232
322
  end
233
323
 
324
+ # :nodoc:
325
+ #
326
+ # Must be called with @mutex held!
327
+ #
328
+ def can_spawn_processor?
329
+ io_processors_count = @processors.count(&:marked_as_io_thread?)
330
+ extra_io_processors_count = io_processors_count > @max_io_threads ? io_processors_count - @max_io_threads : 0
331
+ (@spawned - io_processors_count) < (@max - extra_io_processors_count)
332
+ end
333
+
234
334
  # Add +work+ to the todo list for a Thread to pickup and process.
235
335
  def <<(work)
236
336
  with_mutex do
@@ -239,78 +339,26 @@ module Puma
239
339
  end
240
340
 
241
341
  @todo << work
342
+ t = @todo.size
343
+ @backlog_max = t if t > @backlog_max
242
344
 
243
- if @waiting < @todo.size and @spawned < @max
345
+ if @waiting < @todo.size and can_spawn_processor?
244
346
  spawn_thread
245
347
  end
246
348
 
247
349
  @not_empty.signal
248
350
  end
351
+ self
249
352
  end
250
353
 
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
354
+ def spawn_thread_if_needed # :nodoc:
278
355
  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
356
+ if @waiting < @todo.size and can_spawn_processor?
357
+ spawn_thread
289
358
  end
290
359
  end
291
360
  end
292
361
 
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
362
  # If there are any free threads in the pool, tell one to go ahead
315
363
  # and exit. If +force+ is true, then a trim request is requested
316
364
  # even if all threads are being utilized.
@@ -329,16 +377,12 @@ module Puma
329
377
  # spawned counter so that new healthy threads could be created again.
330
378
  def reap
331
379
  with_mutex do
332
- dead_workers = @workers.reject(&:alive?)
380
+ @processors, dead_processors = @processors.partition(&:alive?)
333
381
 
334
- dead_workers.each do |worker|
335
- worker.kill
382
+ dead_processors.each do |processor|
383
+ processor.kill
336
384
  @spawned -= 1
337
385
  end
338
-
339
- @workers.delete_if do |w|
340
- dead_workers.include?(w)
341
- end
342
386
  end
343
387
  end
344
388
 
@@ -397,7 +441,7 @@ module Puma
397
441
  # Next, wait an extra +@shutdown_grace_time+ seconds then force-kill remaining
398
442
  # threads. Finally, wait 1 second for remaining threads to exit.
399
443
  #
400
- def shutdown(timeout=-1)
444
+ def shutdown(timeout)
401
445
  threads = with_mutex do
402
446
  @shutdown = true
403
447
  @trim_requested = @spawned
@@ -406,8 +450,12 @@ module Puma
406
450
 
407
451
  @auto_trim&.stop
408
452
  @reaper&.stop
409
- # dup workers so that we join them all safely
410
- @workers.dup
453
+ # dup processors so that we join them all safely
454
+ @processors.dup
455
+ end
456
+
457
+ if @shutdown_debug == true
458
+ shutdown_debug("Shutdown initiated")
411
459
  end
412
460
 
413
461
  if timeout == -1
@@ -417,13 +465,16 @@ module Puma
417
465
  join = ->(inner_timeout) do
418
466
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
419
467
  threads.reject! do |t|
420
- elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
421
- t.join inner_timeout - elapsed
468
+ remaining = inner_timeout - (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
469
+ remaining > 0 && t.join(remaining)
422
470
  end
423
471
  end
424
472
 
425
473
  # Wait +timeout+ seconds for threads to finish.
426
474
  join.call(timeout)
475
+ if @shutdown_debug == :on_force && !threads.empty?
476
+ shutdown_debug("Shutdown timeout exceeded")
477
+ end
427
478
 
428
479
  # If threads are still running, raise ForceShutdown and wait to finish.
429
480
  @shutdown_mutex.synchronize do
@@ -433,6 +484,9 @@ module Puma
433
484
  end
434
485
  end
435
486
  join.call(@shutdown_grace_time)
487
+ if @shutdown_debug == :on_force && !threads.empty?
488
+ shutdown_debug("Shutdown grace timeout exceeded")
489
+ end
436
490
 
437
491
  # If threads are _still_ running, forcefully kill them and wait to finish.
438
492
  threads.each(&:kill)
@@ -440,7 +494,24 @@ module Puma
440
494
  end
441
495
 
442
496
  @spawned = 0
443
- @workers = []
497
+ @processors = []
498
+ end
499
+
500
+ private
501
+
502
+ def shutdown_debug(message)
503
+ pid = Process.pid
504
+ threads = Thread.list
505
+
506
+ $stdout.syswrite "#{pid}: #{message}\n"
507
+ $stdout.syswrite "#{pid}: === Begin thread backtrace dump ===\n"
508
+
509
+ threads.each_with_index do |thread, index|
510
+ $stdout.syswrite "#{pid}: Thread #{index + 1}/#{threads.size}: #{thread.inspect}\n"
511
+ $stdout.syswrite "#{pid}: #{(thread.backtrace || []).join("\n#{pid}: ")}\n\n"
512
+ end
513
+
514
+ $stdout.syswrite "#{pid}: === End thread backtrace dump ===\n"
444
515
  end
445
516
  end
446
517
  end
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
@@ -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, :log_writer => log_writer, events: @events)
75
+ launcher = ::Puma::Launcher.new(conf, log_writer: log_writer, events: @events)
76
76
 
77
77
  yield launcher if block_given?
78
78
  begin
@@ -109,7 +109,7 @@ module Puma
109
109
  end
110
110
 
111
111
  if port
112
- host ||= ::Puma::Configuration::DEFAULTS[:tcp_host]
112
+ host ||= ::Puma::Configuration.default_tcp_host
113
113
  config.port port, host
114
114
  end
115
115
  end
data/tools/Dockerfile CHANGED
@@ -1,16 +1,26 @@
1
1
  # Use this Dockerfile to create minimal reproductions of issues
2
+ # Build (MRI): docker build -f tools/Dockerfile .
3
+ # Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
2
4
 
3
- FROM ruby:3.2
5
+ ARG RUBY_IMAGE=ruby:latest
6
+ FROM ${RUBY_IMAGE}
4
7
 
5
- # throw errors if Gemfile has been modified since Gemfile.lock
6
- RUN bundle config --global frozen 1
8
+ # Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
9
+ ARG BUNDLE_FROZEN=true
10
+
11
+ RUN apt-get update \
12
+ && apt-get install -y --no-install-recommends ragel procps git \
13
+ && rm -rf /var/lib/apt/lists/*
14
+
15
+ # Only freeze Bundler and compile native extensions when using MRI.
16
+ RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
7
17
 
8
18
  WORKDIR /usr/src/app
9
19
 
10
20
  COPY . .
11
21
 
12
22
  RUN bundle install
13
- RUN bundle exec rake compile
23
+ RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi
14
24
 
15
25
  EXPOSE 9292
16
- CMD bundle exec bin/puma test/rackup/hello.ru
26
+ 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: 6.6.0
4
+ version: 8.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-28 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: nio4r
@@ -43,13 +43,21 @@ files:
43
43
  - bin/puma
44
44
  - bin/puma-wild
45
45
  - bin/pumactl
46
+ - docs/5.0-Upgrade.md
47
+ - docs/6.0-Upgrade.md
48
+ - docs/7.0-Upgrade.md
49
+ - docs/8.0-Upgrade.md
46
50
  - docs/architecture.md
47
51
  - docs/compile_options.md
48
52
  - docs/deployment.md
49
53
  - docs/fork_worker.md
54
+ - docs/grpc.md
55
+ - docs/images/favicon.svg
50
56
  - docs/images/puma-connection-flow-no-reactor.png
51
57
  - docs/images/puma-connection-flow.png
52
58
  - docs/images/puma-general-arch.png
59
+ - docs/images/running-puma.svg
60
+ - docs/images/standard-logo.svg
53
61
  - docs/java_options.md
54
62
  - docs/jungle/README.md
55
63
  - docs/jungle/rc.d/README.md
@@ -66,7 +74,6 @@ files:
66
74
  - docs/testing_benchmarks_local_files.md
67
75
  - docs/testing_test_rackup_ci_files.md
68
76
  - ext/puma_http11/PumaHttp11Service.java
69
- - ext/puma_http11/ext_help.h
70
77
  - ext/puma_http11/extconf.rb
71
78
  - ext/puma_http11/http11_parser.c
72
79
  - ext/puma_http11/http11_parser.h
@@ -75,6 +82,7 @@ files:
75
82
  - ext/puma_http11/http11_parser_common.rl
76
83
  - ext/puma_http11/mini_ssl.c
77
84
  - ext/puma_http11/no_ssl/PumaHttp11Service.java
85
+ - ext/puma_http11/org/jruby/puma/EnvKey.java
78
86
  - ext/puma_http11/org/jruby/puma/Http11.java
79
87
  - ext/puma_http11/org/jruby/puma/Http11Parser.java
80
88
  - ext/puma_http11/org/jruby/puma/MiniSSL.java
@@ -84,9 +92,11 @@ files:
84
92
  - lib/puma/binder.rb
85
93
  - lib/puma/cli.rb
86
94
  - lib/puma/client.rb
95
+ - lib/puma/client_env.rb
87
96
  - lib/puma/cluster.rb
88
97
  - lib/puma/cluster/worker.rb
89
98
  - lib/puma/cluster/worker_handle.rb
99
+ - lib/puma/cluster_accept_loop_delay.rb
90
100
  - lib/puma/commonlogger.rb
91
101
  - lib/puma/configuration.rb
92
102
  - lib/puma/const.rb
@@ -111,10 +121,11 @@ files:
111
121
  - lib/puma/rack/urlmap.rb
112
122
  - lib/puma/rack_default.rb
113
123
  - lib/puma/reactor.rb
114
- - lib/puma/request.rb
124
+ - lib/puma/response.rb
115
125
  - lib/puma/runner.rb
116
126
  - lib/puma/sd_notify.rb
117
127
  - lib/puma/server.rb
128
+ - lib/puma/server_plugin_control.rb
118
129
  - lib/puma/single.rb
119
130
  - lib/puma/state_file.rb
120
131
  - lib/puma/thread_pool.rb
@@ -127,10 +138,11 @@ licenses:
127
138
  - BSD-3-Clause
128
139
  metadata:
129
140
  bug_tracker_uri: https://github.com/puma/puma/issues
130
- changelog_uri: https://github.com/puma/puma/blob/master/History.md
141
+ changelog_uri: https://github.com/puma/puma/blob/main/History.md
131
142
  homepage_uri: https://puma.io
132
143
  source_code_uri: https://github.com/puma/puma
133
144
  rubygems_mfa_required: 'true'
145
+ msys2_mingw_dependencies: openssl
134
146
  rdoc_options: []
135
147
  require_paths:
136
148
  - lib
@@ -138,14 +150,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
150
  requirements:
139
151
  - - ">="
140
152
  - !ruby/object:Gem::Version
141
- version: '2.4'
153
+ version: '3.0'
142
154
  required_rubygems_version: !ruby/object:Gem::Requirement
143
155
  requirements:
144
156
  - - ">="
145
157
  - !ruby/object:Gem::Version
146
158
  version: '0'
147
159
  requirements: []
148
- rubygems_version: 3.6.3
160
+ rubygems_version: 4.0.6
149
161
  specification_version: 4
150
162
  summary: A Ruby/Rack web server built for parallelism.
151
163
  test_files: []
@@ -1,15 +0,0 @@
1
- #ifndef ext_help_h
2
- #define ext_help_h
3
-
4
- #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "%s", "NULL found for " # T " when shouldn't be.");
5
- #define DATA_GET(from,type,data_type,name) TypedData_Get_Struct(from,type,data_type,name); RAISE_NOT_NULL(name);
6
- #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "%s", "Wrong argument type for " # V " required " # T);
7
- #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
8
-
9
- #ifdef DEBUG
10
- #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
11
- #else
12
- #define TRACE()
13
- #endif
14
-
15
- #endif