puma 7.1.0 → 7.2.1
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 +78 -0
- data/README.md +17 -9
- data/docs/deployment.md +58 -23
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +3 -10
- data/docs/plugins.md +2 -2
- data/docs/signals.md +10 -10
- data/docs/stats.md +1 -1
- data/docs/systemd.md +3 -3
- data/ext/puma_http11/puma_http11.c +101 -109
- data/lib/puma/app/status.rb +10 -2
- data/lib/puma/client.rb +27 -11
- data/lib/puma/cluster/worker.rb +10 -9
- data/lib/puma/cluster.rb +2 -3
- data/lib/puma/configuration.rb +16 -9
- data/lib/puma/const.rb +4 -3
- data/lib/puma/dsl.rb +16 -6
- data/lib/puma/launcher.rb +4 -3
- data/lib/puma/reactor.rb +3 -12
- data/lib/puma/request.rb +10 -8
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +3 -3
- data/lib/puma/single.rb +2 -2
- data/tools/Dockerfile +13 -5
- metadata +3 -4
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/dsl.rb
CHANGED
|
@@ -216,6 +216,8 @@ module Puma
|
|
|
216
216
|
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
|
217
217
|
# @example
|
|
218
218
|
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
|
219
|
+
# @example
|
|
220
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
|
|
219
221
|
#
|
|
220
222
|
def activate_control_app(url="auto", opts={})
|
|
221
223
|
if url == "auto"
|
|
@@ -240,6 +242,7 @@ module Puma
|
|
|
240
242
|
|
|
241
243
|
@options[:control_auth_token] = auth_token
|
|
242
244
|
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
|
245
|
+
@options[:control_data_only] = opts[:data_only] if opts[:data_only]
|
|
243
246
|
end
|
|
244
247
|
|
|
245
248
|
# Load additional configuration from a file.
|
|
@@ -666,21 +669,27 @@ module Puma
|
|
|
666
669
|
@options[:state_permission] = permission
|
|
667
670
|
end
|
|
668
671
|
|
|
669
|
-
# How many worker processes to run.
|
|
670
|
-
#
|
|
672
|
+
# How many worker processes to run. Typically this is set to the number of
|
|
673
|
+
# available cores.
|
|
671
674
|
#
|
|
672
675
|
# The default is the value of the environment variable +WEB_CONCURRENCY+ if
|
|
673
|
-
# set, otherwise 0.
|
|
676
|
+
# set, otherwise 0. Passing +:auto+ will set the value to
|
|
677
|
+
# +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
|
|
678
|
+
# On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
|
|
679
|
+
# will round down. If it rounds down to 0, Puma will run in single mode and
|
|
680
|
+
# cluster-only hooks like +before_worker_boot+ will not execute.
|
|
681
|
+
# If you rely on cluster-only hooks, set an explicit worker count.
|
|
674
682
|
#
|
|
675
|
-
#
|
|
683
|
+
# A value of 0 or nil means run in single mode.
|
|
676
684
|
#
|
|
677
685
|
# @example
|
|
678
686
|
# workers 2
|
|
687
|
+
# workers :auto
|
|
679
688
|
#
|
|
680
689
|
# @see Puma::Cluster
|
|
681
690
|
#
|
|
682
691
|
def workers(count)
|
|
683
|
-
@options[:workers] = count.
|
|
692
|
+
@options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
|
|
684
693
|
end
|
|
685
694
|
|
|
686
695
|
# Disable warning message when running in cluster mode with a single worker.
|
|
@@ -995,6 +1004,7 @@ module Puma
|
|
|
995
1004
|
# The default is +true+ if your app uses more than 1 worker.
|
|
996
1005
|
#
|
|
997
1006
|
# @note Cluster mode only.
|
|
1007
|
+
# @note When using `fork_worker`, this only applies to worker 0.
|
|
998
1008
|
#
|
|
999
1009
|
# @example
|
|
1000
1010
|
# preload_app!
|
|
@@ -1378,7 +1388,7 @@ module Puma
|
|
|
1378
1388
|
#
|
|
1379
1389
|
# The default is +:auto+.
|
|
1380
1390
|
#
|
|
1381
|
-
# @see https://github.com/socketry/nio4r/blob/
|
|
1391
|
+
# @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
|
|
1382
1392
|
#
|
|
1383
1393
|
def io_selector_backend(backend)
|
|
1384
1394
|
@options[:io_selector_backend] = backend.to_sym
|
data/lib/puma/launcher.rb
CHANGED
|
@@ -42,9 +42,11 @@ module Puma
|
|
|
42
42
|
# end
|
|
43
43
|
# Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
|
|
44
44
|
def initialize(conf, launcher_args={})
|
|
45
|
-
## Minimal initialization
|
|
45
|
+
## Minimal initialization before potential early restart (e.g. from bundle pruning)
|
|
46
46
|
|
|
47
47
|
@config = conf
|
|
48
|
+
# Advertise the CLI Configuration before config files are loaded
|
|
49
|
+
Puma.cli_config = @config if defined?(Puma.cli_config)
|
|
48
50
|
@config.clamp
|
|
49
51
|
|
|
50
52
|
@options = @config.options
|
|
@@ -70,8 +72,7 @@ module Puma
|
|
|
70
72
|
|
|
71
73
|
env = launcher_args.delete(:env) || ENV
|
|
72
74
|
|
|
73
|
-
#
|
|
74
|
-
Puma.cli_config = @config if defined?(Puma.cli_config)
|
|
75
|
+
# Log after prune_bundler! to avoid duplicate logging if a restart occurs
|
|
75
76
|
log_config if env['PUMA_LOG_CONFIG']
|
|
76
77
|
|
|
77
78
|
@binder = Binder.new(@log_writer, @options)
|
data/lib/puma/reactor.rb
CHANGED
|
@@ -75,15 +75,12 @@ module Puma
|
|
|
75
75
|
private
|
|
76
76
|
|
|
77
77
|
def select_loop
|
|
78
|
-
close_selector = true
|
|
79
78
|
begin
|
|
80
79
|
until @input.closed? && @input.empty?
|
|
81
80
|
# Wakeup any registered object that receives incoming data.
|
|
82
81
|
# Block until the earliest timeout or Selector#wakeup is called.
|
|
83
82
|
timeout = (earliest = @timeouts.first) && earliest.timeout
|
|
84
|
-
monitor_wake_up = false
|
|
85
83
|
@selector.select(timeout) do |monitor|
|
|
86
|
-
monitor_wake_up = true
|
|
87
84
|
wakeup!(monitor.value)
|
|
88
85
|
end
|
|
89
86
|
|
|
@@ -103,18 +100,12 @@ module Puma
|
|
|
103
100
|
STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
|
|
104
101
|
STDERR.puts e.backtrace
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
# is odd. Regardless, it may continue for thousands of calls if retried.
|
|
108
|
-
# Also, when it raises, @selector.close also raises an error.
|
|
109
|
-
if !monitor_wake_up && NoMethodError === e
|
|
110
|
-
close_selector = false
|
|
111
|
-
else
|
|
112
|
-
retry
|
|
113
|
-
end
|
|
103
|
+
retry
|
|
114
104
|
end
|
|
105
|
+
|
|
115
106
|
# Wakeup all remaining objects on shutdown.
|
|
116
107
|
@timeouts.each(&@block)
|
|
117
|
-
@selector.close
|
|
108
|
+
@selector.close
|
|
118
109
|
end
|
|
119
110
|
|
|
120
111
|
# Start monitoring the object.
|
data/lib/puma/request.rb
CHANGED
|
@@ -36,17 +36,19 @@ module Puma
|
|
|
36
36
|
# Takes the request contained in +client+, invokes the Rack application to construct
|
|
37
37
|
# the response and writes it back to +client.io+.
|
|
38
38
|
#
|
|
39
|
-
# It'll return +
|
|
39
|
+
# It'll return +:close+ when the connection is closed, this doesn't mean
|
|
40
40
|
# that the response wasn't successful.
|
|
41
41
|
#
|
|
42
|
+
# It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
|
|
43
|
+
# Which may contain additional requests.
|
|
44
|
+
#
|
|
42
45
|
# It'll return +:async+ if the connection remains open but will be handled
|
|
43
46
|
# elsewhere, i.e. the connection has been hijacked by the Rack application.
|
|
44
47
|
#
|
|
45
48
|
# Finally, it'll return +true+ on keep-alive connections.
|
|
46
49
|
# @param client [Puma::Client]
|
|
47
50
|
# @param requests [Integer]
|
|
48
|
-
# @return [
|
|
49
|
-
#
|
|
51
|
+
# @return [:close, :keep_alive, :async]
|
|
50
52
|
def handle_request(client, requests)
|
|
51
53
|
env = client.env
|
|
52
54
|
io_buffer = client.io_buffer
|
|
@@ -54,7 +56,7 @@ module Puma
|
|
|
54
56
|
app_body = nil
|
|
55
57
|
error = nil
|
|
56
58
|
|
|
57
|
-
return
|
|
59
|
+
return :close if closed_socket?(socket)
|
|
58
60
|
|
|
59
61
|
if client.http_content_length_limit_exceeded
|
|
60
62
|
return prepare_response(413, {}, ["Payload Too Large"], requests, client)
|
|
@@ -167,13 +169,13 @@ module Puma
|
|
|
167
169
|
# a call to `Server#lowlevel_error`
|
|
168
170
|
# @param requests [Integer] number of inline requests handled
|
|
169
171
|
# @param client [Puma::Client]
|
|
170
|
-
# @return [
|
|
172
|
+
# @return [:close, :keep_alive, :async]
|
|
171
173
|
def prepare_response(status, headers, res_body, requests, client)
|
|
172
174
|
env = client.env
|
|
173
175
|
socket = client.io
|
|
174
176
|
io_buffer = client.io_buffer
|
|
175
177
|
|
|
176
|
-
return
|
|
178
|
+
return :close if closed_socket?(socket)
|
|
177
179
|
|
|
178
180
|
# Close the connection after a reasonable number of inline requests
|
|
179
181
|
force_keep_alive = @enable_keep_alives && client.requests_served < @max_keep_alive
|
|
@@ -244,7 +246,7 @@ module Puma
|
|
|
244
246
|
io_buffer << LINE_END
|
|
245
247
|
fast_write_str socket, io_buffer.read_and_reset
|
|
246
248
|
socket.flush
|
|
247
|
-
return keep_alive
|
|
249
|
+
return keep_alive ? :keep_alive : :close
|
|
248
250
|
end
|
|
249
251
|
else
|
|
250
252
|
if content_length
|
|
@@ -270,7 +272,7 @@ module Puma
|
|
|
270
272
|
fast_write_response socket, body, io_buffer, chunked, content_length.to_i
|
|
271
273
|
body.close if close_body
|
|
272
274
|
# if we're shutting down, close keep_alive connections
|
|
273
|
-
!shutting_down? && keep_alive
|
|
275
|
+
!shutting_down? && keep_alive ? :keep_alive : :close
|
|
274
276
|
end
|
|
275
277
|
|
|
276
278
|
HTTP_ON_VALUES = { "on" => true, HTTPS => true }
|
data/lib/puma/runner.rb
CHANGED
|
@@ -70,7 +70,7 @@ module Puma
|
|
|
70
70
|
token = nil if token.empty? || token == 'none'
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
app = Puma::App::Status.new @launcher, token
|
|
73
|
+
app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
|
|
74
74
|
|
|
75
75
|
# A Reactor is not created and nio4r is not loaded when 'queue_requests: false'
|
|
76
76
|
# Use `nil` for events, no hooks in control server
|
data/lib/puma/server.rb
CHANGED
|
@@ -299,7 +299,7 @@ module Puma
|
|
|
299
299
|
# If read buffering is not done, and no other read buffering is performed (such as by an application server
|
|
300
300
|
# such as nginx) then the application would be subject to a slow client attack.
|
|
301
301
|
#
|
|
302
|
-
# For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/
|
|
302
|
+
# For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
|
|
303
303
|
#
|
|
304
304
|
# The method checks to see if it has the full header and body with
|
|
305
305
|
# the `Puma::Client#try_to_finish` method. If the full request has been sent,
|
|
@@ -501,10 +501,10 @@ module Puma
|
|
|
501
501
|
can_loop = false
|
|
502
502
|
@requests_count += 1
|
|
503
503
|
case handle_request(client, requests + 1)
|
|
504
|
-
when
|
|
504
|
+
when :close
|
|
505
505
|
when :async
|
|
506
506
|
close_socket = false
|
|
507
|
-
when
|
|
507
|
+
when :keep_alive
|
|
508
508
|
requests += 1
|
|
509
509
|
|
|
510
510
|
client.reset
|
data/lib/puma/single.rb
CHANGED
data/tools/Dockerfile
CHANGED
|
@@ -1,18 +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
|
-
|
|
5
|
+
ARG RUBY_IMAGE=ruby:latest
|
|
6
|
+
FROM ${RUBY_IMAGE}
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
|
|
9
|
+
ARG BUNDLE_FROZEN=true
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
9
17
|
|
|
10
18
|
WORKDIR /usr/src/app
|
|
11
19
|
|
|
12
20
|
COPY . .
|
|
13
21
|
|
|
14
22
|
RUN bundle install
|
|
15
|
-
RUN bundle exec rake compile
|
|
23
|
+
RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi
|
|
16
24
|
|
|
17
25
|
EXPOSE 9292
|
|
18
26
|
CMD ["bundle", "exec", "bin/puma", "test/rackup/hello.ru"]
|
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: 7.1
|
|
4
|
+
version: 7.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evan Phoenix
|
|
@@ -66,7 +66,6 @@ files:
|
|
|
66
66
|
- docs/testing_benchmarks_local_files.md
|
|
67
67
|
- docs/testing_test_rackup_ci_files.md
|
|
68
68
|
- ext/puma_http11/PumaHttp11Service.java
|
|
69
|
-
- ext/puma_http11/ext_help.h
|
|
70
69
|
- ext/puma_http11/extconf.rb
|
|
71
70
|
- ext/puma_http11/http11_parser.c
|
|
72
71
|
- ext/puma_http11/http11_parser.h
|
|
@@ -128,7 +127,7 @@ licenses:
|
|
|
128
127
|
- BSD-3-Clause
|
|
129
128
|
metadata:
|
|
130
129
|
bug_tracker_uri: https://github.com/puma/puma/issues
|
|
131
|
-
changelog_uri: https://github.com/puma/puma/blob/
|
|
130
|
+
changelog_uri: https://github.com/puma/puma/blob/main/History.md
|
|
132
131
|
homepage_uri: https://puma.io
|
|
133
132
|
source_code_uri: https://github.com/puma/puma
|
|
134
133
|
rubygems_mfa_required: 'true'
|
|
@@ -147,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
147
146
|
- !ruby/object:Gem::Version
|
|
148
147
|
version: '0'
|
|
149
148
|
requirements: []
|
|
150
|
-
rubygems_version:
|
|
149
|
+
rubygems_version: 4.0.6
|
|
151
150
|
specification_version: 4
|
|
152
151
|
summary: A Ruby/Rack web server built for parallelism.
|
|
153
152
|
test_files: []
|
data/ext/puma_http11/ext_help.h
DELETED
|
@@ -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
|