puma 8.0.3-java → 8.1.0-java
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 +115 -0
- data/README.md +20 -5
- data/docs/6.0-Upgrade.md +1 -1
- data/docs/8.0-Upgrade.md +2 -2
- data/docs/deployment.md +3 -3
- data/docs/fork_worker.md +34 -4
- data/docs/kubernetes.md +3 -3
- data/docs/plugins.md +2 -2
- data/docs/puma_support.md +78 -0
- data/docs/rails_dev_mode.md +2 -2
- data/docs/restart.md +4 -3
- data/docs/signals.md +2 -2
- data/docs/stats.md +5 -5
- data/docs/systemd.md +4 -2
- data/docs/testing_benchmarks_local_files.md +1 -1
- data/docs/testing_test_rackup_ci_files.md +2 -2
- data/ext/puma_http11/extconf.rb +2 -0
- data/ext/puma_http11/http11_parser.c +6 -2
- data/ext/puma_http11/http11_parser_common.rl +4 -1
- data/ext/puma_http11/mini_ssl.c +8 -4
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +36 -36
- data/ext/puma_http11/puma_http11.c +24 -0
- data/lib/puma/binder.rb +29 -0
- data/lib/puma/cli.rb +6 -0
- data/lib/puma/client.rb +75 -29
- data/lib/puma/client_env.rb +32 -18
- data/lib/puma/cluster/worker.rb +109 -33
- data/lib/puma/cluster/worker_handle.rb +16 -0
- data/lib/puma/cluster.rb +173 -44
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +22 -3
- data/lib/puma/const.rb +11 -9
- data/lib/puma/dsl.rb +265 -91
- data/lib/puma/launcher.rb +6 -4
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/plugin/systemd.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/response.rb +13 -5
- data/lib/puma/runner.rb +5 -1
- data/lib/puma/sd_notify.rb +4 -1
- data/lib/puma/server.rb +45 -20
- data/lib/puma/thread_pool.rb +12 -1
- data/lib/puma.rb +1 -1
- metadata +3 -2
data/lib/puma/launcher.rb
CHANGED
|
@@ -78,6 +78,7 @@ module Puma
|
|
|
78
78
|
@binder = Binder.new(@log_writer, @options)
|
|
79
79
|
@binder.create_inherited_fds(env).each { |k| env.delete k }
|
|
80
80
|
@binder.create_activated_fds(env).each { |k| env.delete k }
|
|
81
|
+
@control_activated_socket = @binder.take_activated_socket(@options[:control_url]) if @options[:control_url]
|
|
81
82
|
|
|
82
83
|
@environment = @config.environment
|
|
83
84
|
|
|
@@ -112,7 +113,7 @@ module Puma
|
|
|
112
113
|
@status = :run
|
|
113
114
|
end
|
|
114
115
|
|
|
115
|
-
attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir
|
|
116
|
+
attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir, :control_activated_socket
|
|
116
117
|
|
|
117
118
|
# Return stats about the server
|
|
118
119
|
def stats
|
|
@@ -187,6 +188,9 @@ module Puma
|
|
|
187
188
|
if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
|
|
188
189
|
@runner.fork_worker!
|
|
189
190
|
true
|
|
191
|
+
elsif clustered? && @runner.respond_to?(:mold_worker!) && @options[:mold_worker]
|
|
192
|
+
@runner.mold_worker!
|
|
193
|
+
true
|
|
190
194
|
else
|
|
191
195
|
log "* refork called but not available."
|
|
192
196
|
false
|
|
@@ -197,8 +201,6 @@ module Puma
|
|
|
197
201
|
def run
|
|
198
202
|
previous_env = get_env
|
|
199
203
|
|
|
200
|
-
@config.clamp
|
|
201
|
-
|
|
202
204
|
@config.plugins.fire_starts self
|
|
203
205
|
|
|
204
206
|
setup_signals
|
|
@@ -282,8 +284,8 @@ module Puma
|
|
|
282
284
|
end
|
|
283
285
|
|
|
284
286
|
def do_graceful_stop
|
|
285
|
-
@events.fire_after_stopped!
|
|
286
287
|
@runner.stop_blocked
|
|
288
|
+
@events.fire_after_stopped!
|
|
287
289
|
end
|
|
288
290
|
|
|
289
291
|
def do_restart(previous_env)
|
data/lib/puma/minissl.rb
CHANGED
|
@@ -97,7 +97,7 @@ module Puma
|
|
|
97
97
|
# It would make more sense to let @socket.read_nonblock raise
|
|
98
98
|
# EAGAIN if necessary but it seems like it'll misbehave on Windows.
|
|
99
99
|
# I don't have a Windows machine to debug this so I can't explain
|
|
100
|
-
# exactly
|
|
100
|
+
# exactly what's happening in that OS. Please let me know if you
|
|
101
101
|
# find out!
|
|
102
102
|
#
|
|
103
103
|
# In the meantime, we can emulate the correct behavior by
|
data/lib/puma/plugin/systemd.rb
CHANGED
|
@@ -5,7 +5,7 @@ require_relative '../plugin'
|
|
|
5
5
|
# Puma's systemd integration allows Puma to inform systemd:
|
|
6
6
|
# 1. when it has successfully started
|
|
7
7
|
# 2. when it is starting shutdown
|
|
8
|
-
# 3. periodically for a liveness check with a watchdog thread
|
|
8
|
+
# 3. at startup and then periodically for a liveness check with a watchdog thread
|
|
9
9
|
# 4. periodically set the status
|
|
10
10
|
Puma::Plugin.create do
|
|
11
11
|
def start(launcher)
|
data/lib/puma/puma_http11.jar
CHANGED
|
Binary file
|
data/lib/puma/response.rb
CHANGED
|
@@ -75,6 +75,7 @@ module Puma
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
env["puma.mark_as_io_bound"] = -> { processor.mark_as_io_thread! }
|
|
78
|
+
env["puma.connection_closed?"] = -> { closed_socket?(socket) }
|
|
78
79
|
|
|
79
80
|
begin
|
|
80
81
|
status, headers, app_body = @thread_pool.with_force_shutdown do
|
|
@@ -165,7 +166,7 @@ module Puma
|
|
|
165
166
|
if res_body.respond_to?(:each) && !resp_info[:response_hijack]
|
|
166
167
|
# below converts app_body into body, dependent on app_body's characteristics, and
|
|
167
168
|
# content_length will be set if it can be determined
|
|
168
|
-
if !content_length && !resp_info[:transfer_encoding] && status != 204
|
|
169
|
+
if !content_length && !resp_info[:transfer_encoding] && status != 204 && status != 304
|
|
169
170
|
if res_body.respond_to?(:to_ary) && (array_body = res_body.to_ary) &&
|
|
170
171
|
array_body.is_a?(Array)
|
|
171
172
|
body = array_body.compact
|
|
@@ -176,16 +177,16 @@ module Puma
|
|
|
176
177
|
elsif res_body.respond_to?(:to_path) && (fn = res_body.to_path) &&
|
|
177
178
|
File.readable?(fn)
|
|
178
179
|
body = File.open fn, 'rb'
|
|
179
|
-
content_length = body.size
|
|
180
180
|
close_body = true
|
|
181
|
+
content_length = body.size
|
|
181
182
|
else
|
|
182
183
|
body = res_body
|
|
183
184
|
end
|
|
184
185
|
elsif !res_body.is_a?(::File) && res_body.respond_to?(:to_path) &&
|
|
185
186
|
(fn = res_body.to_path) && File.readable?(fn = res_body.to_path)
|
|
186
187
|
body = File.open fn, 'rb'
|
|
187
|
-
content_length = body.size
|
|
188
188
|
close_body = true
|
|
189
|
+
content_length = body.size
|
|
189
190
|
elsif !res_body.is_a?(::File) && res_body.respond_to?(:filename) &&
|
|
190
191
|
res_body.respond_to?(:bytesize) && File.readable?(fn = res_body.filename)
|
|
191
192
|
# Sprockets::Asset
|
|
@@ -246,10 +247,11 @@ module Puma
|
|
|
246
247
|
end
|
|
247
248
|
|
|
248
249
|
fast_write_response socket, body, io_buffer, chunked, content_length.to_i
|
|
249
|
-
body.close if close_body
|
|
250
250
|
|
|
251
251
|
# if we're shutting down, close keep_alive connections
|
|
252
252
|
!shutting_down? && keep_alive ? :keep_alive : :close
|
|
253
|
+
ensure
|
|
254
|
+
body.close if close_body
|
|
253
255
|
end
|
|
254
256
|
|
|
255
257
|
def write_pending_interim(socket, client)
|
|
@@ -430,6 +432,12 @@ module Puma
|
|
|
430
432
|
end
|
|
431
433
|
private :fetch_status_code
|
|
432
434
|
|
|
435
|
+
def request_has_close?(env)
|
|
436
|
+
conn = env.fetch(HTTP_CONNECTION, "").downcase
|
|
437
|
+
conn.include?(CLOSE) && conn.split(",").any? { |option| option.strip == CLOSE }
|
|
438
|
+
end
|
|
439
|
+
private :request_has_close?
|
|
440
|
+
|
|
433
441
|
# Processes and write headers to the IOBuffer.
|
|
434
442
|
# @param env [Hash] see Puma::Client#env, from request
|
|
435
443
|
# @param status [Integer] the status returned by the Rack application
|
|
@@ -453,7 +461,7 @@ module Puma
|
|
|
453
461
|
http_11 = env[SERVER_PROTOCOL] == HTTP_11
|
|
454
462
|
if http_11
|
|
455
463
|
resp_info[:allow_chunked] = true
|
|
456
|
-
resp_info[:keep_alive] = env
|
|
464
|
+
resp_info[:keep_alive] = !request_has_close?(env)
|
|
457
465
|
|
|
458
466
|
# An optimization. The most common response is 200, so we can
|
|
459
467
|
# reply with the proper 200 status without having to compute
|
data/lib/puma/runner.rb
CHANGED
|
@@ -30,7 +30,7 @@ module Puma
|
|
|
30
30
|
def wakeup!
|
|
31
31
|
return unless @wakeup
|
|
32
32
|
|
|
33
|
-
@wakeup.
|
|
33
|
+
@wakeup.write_nonblock(PIPE_WAKEUP) unless @wakeup.closed?
|
|
34
34
|
|
|
35
35
|
rescue SystemCallError, IOError
|
|
36
36
|
end
|
|
@@ -77,6 +77,10 @@ module Puma
|
|
|
77
77
|
control = Puma::Server.new app, nil,
|
|
78
78
|
{ min_threads: 0, max_threads: 1, queue_requests: false, log_writer: @log_writer }
|
|
79
79
|
|
|
80
|
+
if (activated = @launcher.control_activated_socket)
|
|
81
|
+
control.binder.activated_sockets.store(*activated)
|
|
82
|
+
end
|
|
83
|
+
|
|
80
84
|
begin
|
|
81
85
|
control.binder.parse [str], nil, 'Starting control server'
|
|
82
86
|
rescue Errno::EADDRINUSE, Errno::EACCES => e
|
data/lib/puma/sd_notify.rb
CHANGED
|
@@ -49,8 +49,11 @@ module Puma
|
|
|
49
49
|
WATCHDOG = "WATCHDOG=1"
|
|
50
50
|
FDSTORE = "FDSTORE=1"
|
|
51
51
|
|
|
52
|
+
# @note When the service manager expects watchdog pings, this sends an
|
|
53
|
+
# immediate `WATCHDOG=1` in the same datagram, which closes the watchdog
|
|
54
|
+
# timeout window between startup and the first periodic watchdog tick.
|
|
52
55
|
def self.ready(unset_env=false)
|
|
53
|
-
notify(READY, unset_env)
|
|
56
|
+
notify(watchdog? ? "#{READY}\n#{WATCHDOG}" : READY, unset_env)
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def self.reloading(unset_env=false)
|
data/lib/puma/server.rb
CHANGED
|
@@ -109,6 +109,8 @@ module Puma
|
|
|
109
109
|
@enable_keep_alives &&= @queue_requests
|
|
110
110
|
@io_selector_backend = @options[:io_selector_backend]
|
|
111
111
|
@http_content_length_limit = @options[:http_content_length_limit]
|
|
112
|
+
@continue_callback = @options[:continue_callback]
|
|
113
|
+
@allow_underscore_headers = @options.fetch(:allow_underscore_headers, true)
|
|
112
114
|
@cluster_accept_loop_delay = ClusterAcceptLoopDelay.new(
|
|
113
115
|
workers: @options[:workers],
|
|
114
116
|
max_delay: @options[:wait_for_less_busy_worker] || 0 # Real default is in Configuration::DEFAULTS, this is for unit testing
|
|
@@ -412,13 +414,21 @@ module Puma
|
|
|
412
414
|
# clients until the code is finished.
|
|
413
415
|
pool.wait_while_out_of_band_running
|
|
414
416
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
417
|
+
unless shutting_down?
|
|
418
|
+
if @queue_requests
|
|
419
|
+
if @cluster_accept_loop_delay.on? && (busy_threads_plus_todo = pool.busy_threads) > 0
|
|
420
|
+
delay = @cluster_accept_loop_delay.calculate(
|
|
421
|
+
max_threads: @max_threads,
|
|
422
|
+
busy_threads_plus_todo: busy_threads_plus_todo
|
|
423
|
+
)
|
|
424
|
+
sleep(delay)
|
|
425
|
+
end
|
|
426
|
+
else
|
|
427
|
+
pool.wait_until_not_full
|
|
428
|
+
|
|
429
|
+
# A stop may have arrived while waiting for a thread
|
|
430
|
+
break if check.wait_readable(0) && handle_check
|
|
431
|
+
end
|
|
422
432
|
end
|
|
423
433
|
|
|
424
434
|
io = begin
|
|
@@ -486,12 +496,14 @@ module Puma
|
|
|
486
496
|
client.env_set_http_version = @env_set_http_version
|
|
487
497
|
client.http_content_length_limit = @http_content_length_limit
|
|
488
498
|
client.supported_http_methods = @supported_http_methods
|
|
499
|
+
client.allow_underscore_headers = @allow_underscore_headers
|
|
500
|
+
client.continue_callback = @continue_callback
|
|
489
501
|
client
|
|
490
502
|
end
|
|
491
503
|
|
|
492
504
|
# :nodoc:
|
|
493
505
|
def handle_check
|
|
494
|
-
cmd = @check.
|
|
506
|
+
cmd = @check.sysread 1
|
|
495
507
|
|
|
496
508
|
case cmd
|
|
497
509
|
when STOP_COMMAND
|
|
@@ -568,8 +580,12 @@ module Puma
|
|
|
568
580
|
if @thread_pool.waiting > 0
|
|
569
581
|
can_loop = true
|
|
570
582
|
else
|
|
571
|
-
@thread_pool
|
|
572
|
-
|
|
583
|
+
@thread_pool.with_mutex do
|
|
584
|
+
unless shutting_down?
|
|
585
|
+
@thread_pool << client
|
|
586
|
+
close_socket = false
|
|
587
|
+
end
|
|
588
|
+
end
|
|
573
589
|
end
|
|
574
590
|
elsif @queue_requests
|
|
575
591
|
client.set_timeout @persistent_timeout
|
|
@@ -646,6 +662,13 @@ module Puma
|
|
|
646
662
|
when HttpParserError501
|
|
647
663
|
response_to_error(client, requests, e, 501)
|
|
648
664
|
@log_writer.parse_error e, client
|
|
665
|
+
when ContinueRejected
|
|
666
|
+
status, headers, res_body = e.response
|
|
667
|
+
begin
|
|
668
|
+
prepare_response(status, headers, res_body, requests, client)
|
|
669
|
+
ensure
|
|
670
|
+
res_body.close if res_body.respond_to? :close
|
|
671
|
+
end
|
|
649
672
|
else
|
|
650
673
|
response_to_error(client, requests, e, 500)
|
|
651
674
|
@log_writer.unknown_error e, nil, "Read"
|
|
@@ -708,16 +731,18 @@ module Puma
|
|
|
708
731
|
end
|
|
709
732
|
|
|
710
733
|
def notify_safely(message)
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
#
|
|
714
|
-
|
|
715
|
-
#
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
734
|
+
# Use write_nonblock rather than `<<` or `syswrite`. This method is
|
|
735
|
+
# called from signal handlers (TERM/USR2/INT/HUP, and the cluster
|
|
736
|
+
# worker's SIGTERM trap). On Ruby < 4.0, a blocking write from trap
|
|
737
|
+
# context that is still in flight when handle_servers' ensure block
|
|
738
|
+
# runs IO#close leaves the closing thread parked in IO#close forever
|
|
739
|
+
# (puma#3677). write_nonblock is a single write(2) that never waits,
|
|
740
|
+
# so IO#close has nothing to wait for. If the pipe is full a command
|
|
741
|
+
# is already pending, so dropping this one is harmless.
|
|
742
|
+
notify = @notify
|
|
743
|
+
notify.write_nonblock(message, exception: false) if notify && !notify.closed?
|
|
744
|
+
rescue IOError, NoMethodError, Errno::EPIPE, Errno::EBADF => e
|
|
745
|
+
@log_writer.unknown_error(e, nil, "notify_safely error") if Puma::IS_MRI && RUBY_VERSION > '3.3'
|
|
721
746
|
end
|
|
722
747
|
private :notify_safely
|
|
723
748
|
|
data/lib/puma/thread_pool.rb
CHANGED
|
@@ -7,7 +7,6 @@ require_relative 'server_plugin_control'
|
|
|
7
7
|
|
|
8
8
|
module Puma
|
|
9
9
|
|
|
10
|
-
# Add `Thread#puma_server` and `Thread#puma_server=`
|
|
11
10
|
Thread.attr_accessor(:puma_server)
|
|
12
11
|
|
|
13
12
|
# Internal Docs for A simple thread pool management object.
|
|
@@ -211,6 +210,7 @@ module Puma
|
|
|
211
210
|
processor.marked_as_io_thread = false
|
|
212
211
|
else
|
|
213
212
|
# We're already at max threads, so we exit the extra io thread.
|
|
213
|
+
@spawned -= 1
|
|
214
214
|
@processors.delete(processor)
|
|
215
215
|
trigger_before_thread_exit_hooks
|
|
216
216
|
Thread.exit
|
|
@@ -314,6 +314,17 @@ module Puma
|
|
|
314
314
|
end
|
|
315
315
|
end
|
|
316
316
|
|
|
317
|
+
def wait_until_not_full
|
|
318
|
+
with_mutex do
|
|
319
|
+
while true
|
|
320
|
+
return if @shutdown
|
|
321
|
+
return if (@spawned - @waiting + @todo.size) < @max
|
|
322
|
+
|
|
323
|
+
@not_full.wait @mutex
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
317
328
|
# @version 5.0.0
|
|
318
329
|
def with_mutex(&block)
|
|
319
330
|
@mutex.owned? ?
|
data/lib/puma.rb
CHANGED
|
@@ -82,7 +82,7 @@ module Puma
|
|
|
82
82
|
#
|
|
83
83
|
def self.deprecate_method_change(method_old, method_caller, method_new)
|
|
84
84
|
if method_old == method_caller
|
|
85
|
-
warn "Use '#{method_new}', '#{method_caller}' is deprecated and will be removed in
|
|
85
|
+
warn "Use '#{method_new}', '#{method_caller}' is deprecated and will be removed in Puma v9"
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: puma
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Evan Phoenix
|
|
@@ -65,6 +65,7 @@ files:
|
|
|
65
65
|
- docs/kubernetes.md
|
|
66
66
|
- docs/nginx.md
|
|
67
67
|
- docs/plugins.md
|
|
68
|
+
- docs/puma_support.md
|
|
68
69
|
- docs/rails_dev_mode.md
|
|
69
70
|
- docs/restart.md
|
|
70
71
|
- docs/signals.md
|
|
@@ -157,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
157
158
|
- !ruby/object:Gem::Version
|
|
158
159
|
version: '0'
|
|
159
160
|
requirements: []
|
|
160
|
-
rubygems_version: 4.0.
|
|
161
|
+
rubygems_version: 4.0.21
|
|
161
162
|
specification_version: 4
|
|
162
163
|
summary: A Ruby/Rack web server built for parallelism.
|
|
163
164
|
test_files: []
|