puma 6.4.3 → 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.
- checksums.yaml +4 -4
- data/History.md +448 -8
- data/README.md +110 -51
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +11 -1
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -0
- data/docs/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +6 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +21 -21
- data/docs/stats.md +11 -5
- data/docs/systemd.md +14 -5
- data/ext/puma_http11/extconf.rb +20 -32
- data/ext/puma_http11/http11_parser.java.rl +51 -65
- data/ext/puma_http11/mini_ssl.c +29 -9
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +194 -101
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +71 -85
- data/ext/puma_http11/puma_http11.c +125 -118
- data/lib/puma/app/status.rb +11 -3
- data/lib/puma/binder.rb +22 -12
- data/lib/puma/cli.rb +11 -9
- data/lib/puma/client.rb +233 -136
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +24 -21
- data/lib/puma/cluster/worker_handle.rb +38 -8
- data/lib/puma/cluster.rb +74 -48
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +197 -64
- data/lib/puma/const.rb +23 -12
- data/lib/puma/control_cli.rb +11 -7
- data/lib/puma/detect.rb +13 -0
- data/lib/puma/dsl.rb +483 -127
- data/lib/puma/error_logger.rb +7 -5
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/launcher/bundle_pruner.rb +3 -5
- data/lib/puma/launcher.rb +76 -59
- data/lib/puma/log_writer.rb +17 -11
- data/lib/puma/minissl/context_builder.rb +1 -0
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/null_io.rb +26 -0
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -13
- data/lib/puma/{request.rb → response.rb} +57 -209
- data/lib/puma/runner.rb +15 -17
- data/lib/puma/sd_notify.rb +1 -4
- data/lib/puma/server.rb +200 -104
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +179 -96
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +11 -8
- data/tools/Dockerfile +15 -5
- metadata +26 -16
- data/ext/puma_http11/ext_help.h +0 -15
data/README.md
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="
|
|
2
|
+
<img src="docs/images/standard-logo.svg" alt="Puma logo">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# Puma: A Ruby Web Server Built For Parallelism
|
|
6
6
|
|
|
7
|
-
[](https://codeclimate.com/github/puma/puma)
|
|
9
|
-
[]( https://stackoverflow.com/questions/tagged/puma )
|
|
7
|
+
[](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
|
|
10
8
|
|
|
11
9
|
Puma is a **simple, fast, multi-threaded, and highly parallel HTTP 1.1 server for Ruby/Rack applications**.
|
|
12
10
|
|
|
13
11
|
## Built For Speed & Parallelism
|
|
14
12
|
|
|
15
|
-
Puma is a server for [Rack](https://github.com/rack/rack)-powered HTTP applications written in Ruby. It is:
|
|
13
|
+
Puma is a server for [Rack](https://github.com/rack/rack)-powered HTTP applications written in Ruby. It is:
|
|
16
14
|
* **Multi-threaded**. Each request is served in a separate thread. This helps you serve more requests per second with less memory use.
|
|
17
15
|
* **Multi-process**. "Pre-forks" in cluster mode, using less memory per-process thanks to copy-on-write memory.
|
|
18
16
|
* **Standalone**. With SSL support, zero-downtime rolling restarts and a built-in request bufferer, you can deploy Puma without any reverse proxy.
|
|
@@ -82,10 +80,10 @@ $ bundle exec puma
|
|
|
82
80
|
|
|
83
81
|
## Configuration
|
|
84
82
|
|
|
85
|
-
Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/
|
|
83
|
+
Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
|
|
86
84
|
|
|
87
85
|
You can also find several configuration examples as part of the
|
|
88
|
-
[test](https://github.com/puma/puma/tree/
|
|
86
|
+
[test](https://github.com/puma/puma/tree/main/test/config) suite.
|
|
89
87
|
|
|
90
88
|
For debugging purposes, you can set the environment variable `PUMA_LOG_CONFIG` with a value
|
|
91
89
|
and the loaded configuration will be printed as part of the boot process.
|
|
@@ -102,9 +100,9 @@ Puma will automatically scale the number of threads, from the minimum until it c
|
|
|
102
100
|
|
|
103
101
|
Be aware that additionally Puma creates threads on its own for internal purposes (e.g. handling slow clients). So, even if you specify -t 1:1, expect around 7 threads created in your application.
|
|
104
102
|
|
|
105
|
-
###
|
|
103
|
+
### Cluster mode
|
|
106
104
|
|
|
107
|
-
Puma also offers "
|
|
105
|
+
Puma also offers "cluster mode". Cluster mode `fork`s workers from a master process. Each child process still has its own thread pool. You can tune the number of workers with the `-w` (or `--workers`) flag:
|
|
108
106
|
|
|
109
107
|
```
|
|
110
108
|
$ puma -t 8:32 -w 3
|
|
@@ -116,13 +114,24 @@ Or with the `WEB_CONCURRENCY` environment variable:
|
|
|
116
114
|
$ WEB_CONCURRENCY=3 puma -t 8:32
|
|
117
115
|
```
|
|
118
116
|
|
|
119
|
-
|
|
117
|
+
When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
|
|
120
118
|
|
|
121
|
-
|
|
119
|
+
```ruby
|
|
120
|
+
# config/puma.rb
|
|
121
|
+
workers :auto
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
See [`workers :auto` gotchas](lib/puma/dsl.rb).
|
|
125
|
+
|
|
126
|
+
Note that threads are still used in cluster mode, and the `-t` thread flag setting is per worker, so `-w 2 -t 16:16` will spawn 32 threads in total, with 16 in each worker process.
|
|
127
|
+
|
|
128
|
+
If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
|
|
122
129
|
|
|
123
|
-
|
|
130
|
+
For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
In cluster mode, Puma can "preload" your application. This loads all the application code *prior* to forking. Preloading reduces total memory usage of your application via an operating system feature called [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write).
|
|
133
|
+
|
|
134
|
+
If the number of workers is greater than 1 (and `--prune-bundler` has not been specified), preloading will be enabled by default. Otherwise, you can use the `--preload` flag from the command line:
|
|
126
135
|
|
|
127
136
|
```
|
|
128
137
|
$ puma -w 3 --preload
|
|
@@ -138,51 +147,106 @@ preload_app!
|
|
|
138
147
|
|
|
139
148
|
Preloading can’t be used with phased restart, since phased restart kills and restarts workers one-by-one, and preloading copies the code of master into the workers.
|
|
140
149
|
|
|
141
|
-
|
|
150
|
+
#### Cluster mode hooks
|
|
151
|
+
|
|
152
|
+
When using clustered mode, Puma's configuration DSL provides `before_fork`, `before_worker_boot`, and `after_worker_shutdown`
|
|
153
|
+
hooks to run code when the master process forks, the child workers are booted, and after each child worker exits respectively.
|
|
154
|
+
|
|
155
|
+
It is recommended to use these hooks with `preload_app!`, otherwise constants loaded by your
|
|
156
|
+
application (such as `Rails`) will not be available inside the hooks.
|
|
142
157
|
|
|
143
158
|
```ruby
|
|
144
159
|
# config/puma.rb
|
|
145
|
-
|
|
146
|
-
#
|
|
160
|
+
before_fork do
|
|
161
|
+
# Add code to run inside the Puma master process before it forks a worker child.
|
|
147
162
|
end
|
|
148
|
-
```
|
|
149
163
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
164
|
+
before_worker_boot do
|
|
165
|
+
# Add code to run inside the Puma worker process after forking.
|
|
166
|
+
end
|
|
153
167
|
|
|
154
|
-
|
|
155
|
-
|
|
168
|
+
after_worker_shutdown do |worker_handle|
|
|
169
|
+
# Add code to run inside the Puma master process after a worker exits. `worker.process_status` can be used to get the
|
|
170
|
+
# `Process::Status` of the exited worker.
|
|
171
|
+
end
|
|
172
|
+
```
|
|
156
173
|
|
|
157
|
-
|
|
174
|
+
In addition, there is an `before_refork` and `after_refork` hooks which are used only in [`fork_worker` mode](docs/fork_worker.md),
|
|
175
|
+
when the worker 0 child process forks a grandchild worker:
|
|
158
176
|
|
|
159
177
|
```ruby
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
#
|
|
178
|
+
before_refork do
|
|
179
|
+
# Used only when fork_worker mode is enabled. Add code to run inside the Puma worker 0
|
|
180
|
+
# child process before it forks a grandchild worker.
|
|
163
181
|
end
|
|
164
182
|
```
|
|
165
183
|
|
|
166
|
-
|
|
184
|
+
```ruby
|
|
185
|
+
after_refork do
|
|
186
|
+
# Used only when fork_worker mode is enabled. Add code to run inside the Puma worker 0
|
|
187
|
+
# child process after it forks a grandchild worker.
|
|
188
|
+
end
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Importantly, note the following considerations when Ruby forks a child process:
|
|
192
|
+
|
|
193
|
+
1. File descriptors such as network sockets **are** copied from the parent to the forked
|
|
194
|
+
child process. Dual-use of the same sockets by parent and child will result in I/O conflicts
|
|
195
|
+
such as `SocketError`, `Errno::EPIPE`, and `EOFError`.
|
|
196
|
+
2. Background Ruby threads, including threads used by various third-party gems for connection
|
|
197
|
+
monitoring, etc., are **not** copied to the child process. Often this does not cause
|
|
198
|
+
immediate problems until a third-party connection goes down, at which point there will
|
|
199
|
+
be no supervisor to reconnect it.
|
|
200
|
+
|
|
201
|
+
Therefore, we recommend the following:
|
|
202
|
+
|
|
203
|
+
1. If possible, do not establish any socket connections (HTTP, database connections, etc.)
|
|
204
|
+
inside Puma's master process when booting.
|
|
205
|
+
2. If (1) is not possible, use `before_fork` and `before_refork` to disconnect the parent's socket
|
|
206
|
+
connections when forking, so that they are not accidentally copied to the child process.
|
|
207
|
+
3. Use `before_worker_boot` to restart any background threads on the forked child.
|
|
208
|
+
4. Use `after_refork` to restart any background threads on the parent.
|
|
209
|
+
|
|
210
|
+
#### Master process lifecycle hooks
|
|
211
|
+
|
|
212
|
+
Puma's configuration DSL provides master process lifecycle hooks `after_booted`, `before_restart`, and `after_stopped`
|
|
213
|
+
which may be used to specify code blocks to run on each event:
|
|
167
214
|
|
|
168
215
|
```ruby
|
|
169
216
|
# config/puma.rb
|
|
170
|
-
|
|
171
|
-
#
|
|
217
|
+
after_booted do
|
|
218
|
+
# Add code to run in the Puma master process after it boots,
|
|
219
|
+
# and also after a phased restart completes.
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
before_restart do
|
|
223
|
+
# Add code to run in the Puma master process when it receives
|
|
224
|
+
# a restart command but before it restarts.
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
after_stopped do
|
|
228
|
+
# Add code to run in the Puma master process when it receives
|
|
229
|
+
# a stop command but before it shuts down.
|
|
172
230
|
end
|
|
173
231
|
```
|
|
174
232
|
|
|
175
233
|
### Error handling
|
|
176
234
|
|
|
177
|
-
If
|
|
178
|
-
textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/
|
|
235
|
+
If Puma encounters an error outside of the context of your application, it will respond with a 400/500 and a simple
|
|
236
|
+
textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
|
|
179
237
|
You can specify custom behavior for this scenario. For example, you can report the error to your third-party
|
|
180
238
|
error-tracking service (in this example, [rollbar](https://rollbar.com)):
|
|
181
239
|
|
|
182
240
|
```ruby
|
|
183
|
-
lowlevel_error_handler do |e|
|
|
184
|
-
|
|
185
|
-
|
|
241
|
+
lowlevel_error_handler do |e, env, status|
|
|
242
|
+
if status == 400
|
|
243
|
+
message = "The server could not process the request due to an error, such as an incorrectly typed URL, malformed syntax, or a URL that contains illegal characters.\n"
|
|
244
|
+
else
|
|
245
|
+
message = "An error has occurred, and engineers have been informed. Please reload the page. If you continue to have problems, contact support@example.com\n"
|
|
246
|
+
Rollbar.critical(e)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
[status, {}, [message]]
|
|
186
250
|
end
|
|
187
251
|
```
|
|
188
252
|
|
|
@@ -249,7 +313,7 @@ $ puma -b ssl://localhost:9292 -b tcp://localhost:9393 -C config/use_local_host.
|
|
|
249
313
|
|
|
250
314
|
#### Controlling SSL Cipher Suites
|
|
251
315
|
|
|
252
|
-
To use or avoid specific SSL
|
|
316
|
+
To use or avoid specific SSL ciphers for TLSv1.2 and below, use `ssl_cipher_filter` or `ssl_cipher_list` options.
|
|
253
317
|
|
|
254
318
|
##### Ruby:
|
|
255
319
|
|
|
@@ -263,6 +327,14 @@ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_fil
|
|
|
263
327
|
$ puma -b 'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
|
|
264
328
|
```
|
|
265
329
|
|
|
330
|
+
To configure the available TLSv1.3 ciphersuites, use `ssl_ciphersuites` option (not available for JRuby).
|
|
331
|
+
|
|
332
|
+
##### Ruby:
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_ciphersuites=TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256'
|
|
336
|
+
```
|
|
337
|
+
|
|
266
338
|
See https://www.openssl.org/docs/man1.1.1/man1/ciphers.html for cipher filter format and full list of cipher suites.
|
|
267
339
|
|
|
268
340
|
Disable TLS v1 with the `no_tlsv1` option:
|
|
@@ -279,7 +351,7 @@ To enable verification flags offered by OpenSSL, use `verification_flags` (not a
|
|
|
279
351
|
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN'
|
|
280
352
|
```
|
|
281
353
|
|
|
282
|
-
You can also set multiple verification flags (by separating them with
|
|
354
|
+
You can also set multiple verification flags (by separating them with a comma):
|
|
283
355
|
|
|
284
356
|
```
|
|
285
357
|
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN,CRL_CHECK'
|
|
@@ -320,7 +392,7 @@ Puma has a built-in status and control app that can be used to query and control
|
|
|
320
392
|
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo
|
|
321
393
|
```
|
|
322
394
|
|
|
323
|
-
Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/
|
|
395
|
+
Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
|
|
324
396
|
|
|
325
397
|
You can also interact with the control server via `pumactl`. This command will restart Puma:
|
|
326
398
|
|
|
@@ -352,7 +424,7 @@ $ puma -C "-"
|
|
|
352
424
|
|
|
353
425
|
The other side-effects of setting the environment are whether to show stack traces (in `development` or `test`), and setting RACK_ENV may potentially affect middleware looking for this value to change their behavior. The default puma RACK_ENV value is `development`. You can see all config default values in `Puma::Configuration#puma_default_options` or [configuration.rb](https://github.com/puma/puma/blob/61c6213fbab/lib/puma/configuration.rb#L182-L204).
|
|
354
426
|
|
|
355
|
-
Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/
|
|
427
|
+
Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
|
|
356
428
|
|
|
357
429
|
## Restart
|
|
358
430
|
|
|
@@ -372,19 +444,6 @@ Some platforms do not support all Puma features.
|
|
|
372
444
|
* **Windows**: Cluster mode is not supported due to a lack of fork(2).
|
|
373
445
|
* **Kubernetes**: The way Kubernetes handles pod shutdowns interacts poorly with server processes implementing graceful shutdown, like Puma. See the [kubernetes section of the documentation](docs/kubernetes.md) for more details.
|
|
374
446
|
|
|
375
|
-
## Known Bugs
|
|
376
|
-
|
|
377
|
-
For MRI versions 2.2.7, 2.2.8, 2.2.9, 2.2.10, 2.3.4 and 2.4.1, you may see ```stream closed in another thread (IOError)```. It may be caused by a [Ruby bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem https://rubygems.org/gems/stopgap_13632:
|
|
378
|
-
|
|
379
|
-
```ruby
|
|
380
|
-
if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION
|
|
381
|
-
begin
|
|
382
|
-
require 'stopgap_13632'
|
|
383
|
-
rescue LoadError
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
```
|
|
387
|
-
|
|
388
447
|
## Deployment
|
|
389
448
|
|
|
390
449
|
* Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma).
|
data/docs/5.0-Upgrade.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Welcome to Puma 5: Spoony Bard.
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
>Note: Puma 5 now automatically uses `WEB_CONCURRENCY` env var if set see [this post for an explanation](https://github.com/puma/puma/issues/2393#issuecomment-702352208). If your memory use goes up after upgrading to Puma 5 it indicates you're now running with multiple workers (processes). You can decrease memory use by tuning this number to be lower.
|
|
6
|
+
|
|
7
|
+
Puma 5 brings new experimental performance features, a few quality-of-life features and loads of bugfixes. Here's what you should do:
|
|
8
|
+
|
|
9
|
+
1. Review the Upgrade section below to see if any of 5.0's breaking changes will affect you.
|
|
10
|
+
2. Upgrade to version 5.0 in your Gemfile and deploy.
|
|
11
|
+
3. Try the new performance experiments outlined below and report your results back to the Puma issue tracker.
|
|
12
|
+
|
|
13
|
+
Puma 5 was named Spoony Bard by our newest supercontributor, [@wjordan](https://github.com/puma/puma/commits?author=wjordan). Will brought you one of our new perf features for this release, as well as [many other fixes and refactors.](https://github.com/puma/puma/commits?author=wjordan) If you'd like to name a Puma release in the future, take a look at [CONTRIBUTING.md](../CONTRIBUTING.md) and get started helping us out :)
|
|
14
|
+
|
|
15
|
+
Puma 5 also welcomes [@MSP-Greg](https://github.com/puma/puma/commits?author=MSP-Greg) as our newest committer. Greg has been instrumental in improving our CI setup and SSL features. Greg also [named our 4.3.0 release](https://github.com/puma/puma/releases/tag/v4.3.0): Mysterious Traveller.
|
|
16
|
+
|
|
17
|
+
## What's New
|
|
18
|
+
|
|
19
|
+
Puma 5 contains three new "experimental" performance features for cluster-mode Pumas running on MRI.
|
|
20
|
+
|
|
21
|
+
If you try any of these features, please report your results to [our report issue](https://github.com/puma/puma/issues/2258).
|
|
22
|
+
|
|
23
|
+
Part of the reason we're calling them _experimental_ is because we're not sure if they'll actually have any benefit. People's workloads in the real world are often not what we anticipate, and synthetic benchmarks are usually not of any help in figuring out if a change will be beneficial or not.
|
|
24
|
+
|
|
25
|
+
We do not believe any of the new features will have a negative effect or impact the stability of your application. This is either a "it works" or "it does nothing" experiment.
|
|
26
|
+
|
|
27
|
+
If any of the features turn out to be particularly beneficial, we may make them defaults in future versions of Puma.
|
|
28
|
+
|
|
29
|
+
### Lower latency, better throughput
|
|
30
|
+
|
|
31
|
+
From our friends at GitLab, the new experimental `wait_for_less_busy_worker` config option may reduce latency and improve throughput for high-load Puma apps on MRI. See the [pull request](https://github.com/puma/puma/pull/2079) for more discussion.
|
|
32
|
+
|
|
33
|
+
Users of this option should see reduced request queue latency and possibly less overall latency.
|
|
34
|
+
|
|
35
|
+
Add the following to your `puma.rb` to try it:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
wait_for_less_busy_worker
|
|
39
|
+
# or
|
|
40
|
+
wait_for_less_busy_worker 0.001
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Production testing at GitLab suggests values between `0.001` and `0.010` are best.
|
|
44
|
+
|
|
45
|
+
### Better memory usage
|
|
46
|
+
|
|
47
|
+
5.0 brings two new options to your config which may improve memory usage.
|
|
48
|
+
|
|
49
|
+
#### nakayoshi_fork
|
|
50
|
+
|
|
51
|
+
`nakayoshi_fork` calls GC a handful of times and compacts the heap on Ruby 2.7+ before forking. This may reduce memory usage of Puma on MRI with preload enabled. It's inspired by [Koichi Sasada's work](https://github.com/ko1/nakayoshi_fork).
|
|
52
|
+
|
|
53
|
+
To use it, you can add this to your `puma.rb`:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
nakayoshi_fork
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### fork_worker
|
|
60
|
+
|
|
61
|
+
Puma 5 introduces an experimental new cluster-mode configuration option, `fork_worker` (`--fork-worker` from the CLI). This mode causes Puma to fork additional workers from worker 0, instead of directly from the master process:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
10000 \_ puma 4.3.3 (tcp://0.0.0.0:9292) [puma]
|
|
65
|
+
10001 \_ puma: cluster worker 0: 10000 [puma]
|
|
66
|
+
10002 \_ puma: cluster worker 1: 10000 [puma]
|
|
67
|
+
10003 \_ puma: cluster worker 2: 10000 [puma]
|
|
68
|
+
10004 \_ puma: cluster worker 3: 10000 [puma]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It is compatible with phased restarts. It also may improve memory usage because the worker process loads additional code after processing requests.
|
|
72
|
+
|
|
73
|
+
To learn more about using `refork` and `fork_worker`, see ['Fork Worker'](fork_worker.md).
|
|
74
|
+
|
|
75
|
+
### What else is new?
|
|
76
|
+
|
|
77
|
+
* **Loads of bugfixes**.
|
|
78
|
+
* Faster phased restarts and worker timeouts.
|
|
79
|
+
* pumactl now has a `thread-backtraces` command to print thread backtraces, bringing thread backtrace printing to all platforms, not just *BSD and Mac. (#2053)
|
|
80
|
+
* Added incrementing `requests_count` to `Puma.stats`. (#2106)
|
|
81
|
+
* Faster phased restart and worker timeout. (#2220)
|
|
82
|
+
* Added `state_permission` to config DSL to set state file permissions (#2238)
|
|
83
|
+
* Ruby 2.2 support will be dropped in Puma 6. This is the final major release series for Ruby 2.2.
|
|
84
|
+
|
|
85
|
+
## Upgrade
|
|
86
|
+
|
|
87
|
+
* Setting the `WEB_CONCURRENCY` environment variable will now configure the number of workers (processes) that Puma will boot and enable preloading of the application.
|
|
88
|
+
* If you did not explicitly set `environment` before, Puma now checks `RAILS_ENV` and will use that, if available in addition to `RACK_ENV`.
|
|
89
|
+
* If you have been using the `--control` CLI option, update your scripts to use `--control-url`.
|
|
90
|
+
* If you are using `worker_directory` in your config file, change it to `directory`.
|
|
91
|
+
* If you are running MRI, default thread count on Puma is now 5, not 16. This may change the amount of threads running in your threadpool. We believe 5 is a better default for most Ruby web applications on MRI. Higher settings increase latency by causing GVL contention.
|
|
92
|
+
* If you are using a worker count of more than 1, set using `WEB_CONCURRENCY`, Puma will now preload the application by default (disable with `preload_app! false`). We believe this is a better default, but may cause issues in non-Rails applications if you do not have the proper `before` and `after` fork hooks configured. See documentation for your framework. Rails users do not need to change anything. **Please note that it is not possible to use [the phased restart](restart.md) with preloading.**
|
|
93
|
+
* tcp mode and daemonization have been removed without replacement. For daemonization, please use a modern process management solution, such as systemd or monit.
|
|
94
|
+
* `connected_port` was renamed to `connected_ports` and now returns an Array, not an Integer.
|
|
95
|
+
|
|
96
|
+
Then, update your Gemfile:
|
|
97
|
+
|
|
98
|
+
`gem 'puma', '< 6'`
|
data/docs/6.0-Upgrade.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Welcome to Puma 6: Sunflower.
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Puma 6 brings performance improvements for most applications, experimental Rack 3 support, support for Sidekiq 7 Capsules, and more.
|
|
6
|
+
|
|
7
|
+
Here's what you should do:
|
|
8
|
+
|
|
9
|
+
1. Review the Upgrade section below to look for breaking changes that could affect you.
|
|
10
|
+
2. Upgrade to version 6.0 in your Gemfile and deploy.
|
|
11
|
+
3. Open up a new bug issue if you find any problems.
|
|
12
|
+
4. Join us in building Puma! We welcome first-timers. See [CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
13
|
+
|
|
14
|
+
For a complete list of changes, see [History.md](../History.md).
|
|
15
|
+
|
|
16
|
+
## What's New
|
|
17
|
+
|
|
18
|
+
Puma 6 is mostly about a few nice-to-have performance changes, and then a few breaking API changes we've been putting off for a while.
|
|
19
|
+
|
|
20
|
+
### Improved Performance
|
|
21
|
+
|
|
22
|
+
We've improved throughput and latency in Puma 6 in a few areas.
|
|
23
|
+
|
|
24
|
+
1. **Large chunked response body throughput 3-10x higher** Chunked response bodies >100kb should be 3 to 10 times faster than in Puma 5. String response bodies should be ~10% faster.
|
|
25
|
+
2. **File response throughput is 3x higher.** File responses (e.g. assets) should be about 3x faster.
|
|
26
|
+
3. **wait_for_less_busy_worker is now default, meaning lower latencies for high-utilization servers** `wait_for_less_busy_worker` was an experimental feature in Puma 5 and it's now the default in Puma 6. This feature makes each Puma child worker in cluster mode wait before listening on the socket, and that wait time is proportional to N * `number_of_threads_responding_to_requests`. This means that it's more likely that a request is picked up by the least-loaded Puma child worker listening on the socket. Many users reported back that this option was stable and decreased average latency, particularly in environments with high load and utilization.
|
|
27
|
+
|
|
28
|
+
### Experimental Rack 3 Support
|
|
29
|
+
|
|
30
|
+
[Rack 3 is now out](https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md) and we've started on Rack 3 support. Please open a bug if you find any incompatibilites.
|
|
31
|
+
|
|
32
|
+
### Sidekiq 7 Capsules
|
|
33
|
+
|
|
34
|
+
Sidekiq 7 (releasing soon) introduces Capsules, which allows you to run a Sidekiq server inside your Puma server (or any other Ruby process for that matter). We've added support by allowing you to pass data into `run_hooks`, see [issue #2915](https://github.com/puma/puma/issues/2915).
|
|
35
|
+
|
|
36
|
+
## Upgrade
|
|
37
|
+
|
|
38
|
+
Check the following list to see if you're depending on any of these behaviors:
|
|
39
|
+
|
|
40
|
+
1. Configuration constants like `DefaultRackup` removed, see [#2928](https://github.com/puma/puma/pull/2928/files#diff-2dc4e3e83be7fd97cebc482ae07d6a8216944003de82458783fb00b5ae9524c8) for the full list.
|
|
41
|
+
1. We have changed the names of the following environment variables: `DISABLE_SSL` is now `PUMA_DISABLE_SSL`, and `MAKE_WARNINGS_INTO_ERRORS` is now `PUMA_MAKE_WARNINGS_INTO_ERRORS`.
|
|
42
|
+
1. Nakayoshi GC (`nakayoshi_fork` option in config) has been removed without replacement.
|
|
43
|
+
1. `wait_for_less_busy_worker` is now on by default. If you don't want to use this feature, you must add `wait_for_less_busy_worker 0` in your config.
|
|
44
|
+
1. We've removed the following public methods on Puma::Server: `Puma::Server#min_threads`, `Puma::Server#max_threads`. Instead, you can pass in configuration as an option to Puma::Server#new. This might make certain gems break (`capybara` for example).
|
|
45
|
+
1. We've removed the following constants: `Puma::StateFile::FIELDS`, `Puma::CLI::KEYS_NOT_TO_PERSIST_IN_STATE` and `Puma::Launcher::KEYS_NOT_TO_PERSIST_IN_STATE`, and `Puma::ControlCLI::COMMANDS`.
|
|
46
|
+
1. We no longer support Ruby 2.2, 2.3, or JRuby on Java 1.7 or below.
|
|
47
|
+
1. The behavior of `remote_addr` has changed. When using the set_remote_address header: "header_name" functionality, if the header is not passed, REMOTE_ADDR is now set to the physical peeraddr instead of always being set to 127.0.0.1. When an error occurs preventing the physical peeraddr from being fetched, REMOTE_ADDR is now set to the unspecified source address ('0.0.0.0') instead of to '127.0.0.1'
|
|
48
|
+
1. Previously, Puma supported anything as an HTTP method and passed it to the app. We now only accept the following 8 HTTP methods, based on [RFC 9110, section 9.1](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.1). The [IANA HTTP Method Registry](https://www.iana.org/assignments/http-methods/http-methods.xhtml) contains a full list of HTTP methods.
|
|
49
|
+
```
|
|
50
|
+
HEAD GET POST PUT DELETE OPTIONS TRACE PATCH
|
|
51
|
+
```
|
|
52
|
+
As of Puma 6.2, these can be overridden by `supported_http_methods` in your config file, see `Puma::DSL#supported_http_methods`.
|
|
53
|
+
|
|
54
|
+
Then, update your Gemfile:
|
|
55
|
+
|
|
56
|
+
`gem 'puma', '< 7'`
|
data/docs/7.0-Upgrade.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Welcome to Puma 7: Romantic Warrior.
|
|
2
|
+
|
|
3
|
+
Puma 7 brings better tail latency for keepalive-heavy traffic, support for fiber-per-request runtimes, and a handful of cleanup and compatibility changes across the server.
|
|
4
|
+
|
|
5
|
+
Here's what you should do:
|
|
6
|
+
|
|
7
|
+
1. Review the Upgrade section below to look for breaking changes that could affect you.
|
|
8
|
+
2. Upgrade to version 7.0 in your Gemfile and deploy.
|
|
9
|
+
3. Open up a new bug issue if you find any problems.
|
|
10
|
+
4. Join us in building Puma! We welcome first-timers. See [CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
11
|
+
|
|
12
|
+
For a complete list of changes, see [History.md](../History.md).
|
|
13
|
+
|
|
14
|
+
## What's New
|
|
15
|
+
|
|
16
|
+
Puma 7 is focused on request lifecycle improvements and long-request correctness.
|
|
17
|
+
|
|
18
|
+
1. **Better tail behavior for keepalive connections.** Puma 7 includes a high-effort fix for long tail response behavior with keepalive clients.
|
|
19
|
+
2. **Fiber-per-request support.** Puma now supports fiber-per-request execution.
|
|
20
|
+
3. **`rack.response_finished` support.** Puma now supports the Rack hook for response completion.
|
|
21
|
+
4. **Custom request logging support.** You can plug in a custom logger for request logs.
|
|
22
|
+
|
|
23
|
+
## Upgrade
|
|
24
|
+
|
|
25
|
+
Check the following list to see if you're depending on any of these behaviors:
|
|
26
|
+
|
|
27
|
+
1. The default `max_keep_alive` is now `999`.
|
|
28
|
+
1. The default `persistent_timeout` is now `65` seconds.
|
|
29
|
+
1. Hook methods now raise `ArgumentError` if called without a block.
|
|
30
|
+
1. For Rack > 3.1, Puma no longer sets `env['HTTP_VERSION']`.
|
|
31
|
+
1. `Puma::Runner#ruby_engine` has been removed.
|
|
32
|
+
1. `preload_app!` is now the default in cluster mode. If you need the old behavior, set `preload_app! false` explicitly.
|
|
33
|
+
1. `Puma::Configuration` must be `clamp`-ed before reading values.
|
|
34
|
+
1. Response headers are now normalized to lowercase.
|
|
35
|
+
1. The minimum supported Ruby version is now 3.0.
|
|
36
|
+
1. Callback hook names have been renamed:
|
|
37
|
+
|
|
38
|
+
| Old hook name | New hook name |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `on_worker_boot` | `before_worker_boot` |
|
|
41
|
+
| `on_worker_shutdown` | `before_worker_shutdown` |
|
|
42
|
+
| `on_restart` | `before_restart` |
|
|
43
|
+
| `on_booted` | `after_booted` |
|
|
44
|
+
| `on_stopped` | `after_stopped` |
|
|
45
|
+
| `on_refork` | `before_refork` |
|
|
46
|
+
| `on_thread_start` | `before_thread_start` |
|
|
47
|
+
| `on_thread_exit` | `before_thread_exit` |
|
|
48
|
+
| `on_worker_fork` | `before_worker_fork` |
|
|
49
|
+
|
|
50
|
+
Then, update your Gemfile:
|
|
51
|
+
|
|
52
|
+
`gem 'puma', '< 8'`
|
data/docs/8.0-Upgrade.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Welcome to Puma 8.0: Into the Arena.
|
|
2
|
+
|
|
3
|
+
Puma 8 brings IPv6 by default, increased control over the threadpool, and more.
|
|
4
|
+
|
|
5
|
+
Here's what you should do:
|
|
6
|
+
|
|
7
|
+
1. Review the Upgrade section below to look for breaking changes that could affect you.
|
|
8
|
+
2. Upgrade to version 8.0 in your Gemfile and deploy.
|
|
9
|
+
3. Open up a new bug issue if you find any problems.
|
|
10
|
+
4. Join us in building Puma! We welcome first-timers. See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
11
|
+
|
|
12
|
+
For a complete list of changes, see [History.md](./History.md).
|
|
13
|
+
|
|
14
|
+
## What's New
|
|
15
|
+
|
|
16
|
+
### Smarter concurrency controls
|
|
17
|
+
|
|
18
|
+
**IO-bound requests can now go past your normal thread ceiling.** Puma 8 adds `max_io_threads` and injects `env["puma.mark_as_io_bound"]` into the Rack env so your app or middleware can tell Puma when a request has become mostly I/O wait. That helps mixed workloads a lot: slow API calls, report generation, and similar wait-heavy requests no longer need to crowd out CPU-bound work as aggressively. This landed in [#3816](https://github.com/puma/puma/pull/3816) and was refined in [#3894](https://github.com/puma/puma/pull/3894).
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# config/puma.rb
|
|
22
|
+
threads 0, 5
|
|
23
|
+
max_io_threads 5
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
# config.ru
|
|
28
|
+
run lambda { |env|
|
|
29
|
+
env['puma.mark_as_io_bound'].call
|
|
30
|
+
report = SlowReportService.fetch
|
|
31
|
+
|
|
32
|
+
[200, { 'content-type' => 'application/json' }, [report]]
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
We anticipate this will mainly by used by framework authors who have threads or types of requests they know are extremely IO-bound, and don't recommend it for use at the application level.
|
|
37
|
+
|
|
38
|
+
**Thread pool limits can be changed at runtime.** Puma now exposes `Puma::Server#update_thread_pool_min_max`, and hook/plugin code can do the same through `Puma::ServerPluginControl`.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# from a plugin or other trusted in-process integration
|
|
42
|
+
server.update_thread_pool_min_max(min: 2, max: 12)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If you already use `before_thread_start`, note that hook behavior changed in this release; see the Upgrade section below.
|
|
46
|
+
|
|
47
|
+
### Cleaner config for single and cluster mode
|
|
48
|
+
|
|
49
|
+
**New `single` and `cluster` blocks let one config file express both modes cleanly.** These blocks run after config files are loaded, so you can keep the mode-specific settings in one obvious place instead of scattering `if` logic through `config/puma.rb`. This makes shared configs much easier to read and reuse across development, review apps, and production. See [#3621](https://github.com/puma/puma/pull/3621).
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
workers ENV.fetch('WEB_CONCURRENCY', 0)
|
|
53
|
+
|
|
54
|
+
single do
|
|
55
|
+
silence_fork_callback_warning
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Only runs if workers > 0
|
|
59
|
+
cluster do
|
|
60
|
+
preload_app!
|
|
61
|
+
before_worker_boot do
|
|
62
|
+
# Do a thing
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Better debugging and operations
|
|
68
|
+
|
|
69
|
+
**`shutdown_debug` can now be limited to forced shutdowns.** If you want thread backtraces only when a graceful shutdown turns into a forced one, use `shutdown_debug on_force: true`. That keeps normal deploy logs quieter while still giving you the "what is hanging?" escape hatch when you need it. See [#3671](https://github.com/puma/puma/pull/3671).
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
shutdown_debug on_force: true
|
|
73
|
+
force_shutdown_after 30
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Thread backtrace via signal works on more platforms.** On systems without `SIGINFO`, Puma now uses `SIGPWR` for thread backtrace dumps. See [#3829](https://github.com/puma/puma/pull/3829).
|
|
77
|
+
|
|
78
|
+
**Phased restart is safer with `fork_worker`.** Puma no longer reforks from a stale worker 0 during phased restarts in `fork_worker` mode. There is nothing new to configure, but if you have tooling that watches worker order, check the Upgrade section because the rollout sequence changed. See [#3853](https://github.com/puma/puma/pull/3853).
|
|
79
|
+
|
|
80
|
+
### Networking and performance
|
|
81
|
+
|
|
82
|
+
**Puma now prefers IPv6 wildcard binds when the host supports them.** When Puma detects a non-loopback IPv6 interface, the default TCP host becomes `::` and the default bind becomes `tcp://[::]:PORT`. That lines Puma up better with modern dual-stack hosts, while still falling back to IPv4 when IPv6 is unavailable. See [#3847](https://github.com/puma/puma/pull/3847). If you need IPv4-only behavior, pin the bind explicitly.
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
bind 'tcp://0.0.0.0:9292'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**There are also a couple of hot-path performance wins.** JRuby gets a faster HTTP parser with fewer copies and cheaper lookups, and Puma now avoids redundant header key downcasing when building responses. See [#3838](https://github.com/puma/puma/pull/3838) and [#3874](https://github.com/puma/puma/pull/3874).
|
|
89
|
+
|
|
90
|
+
## Upgrade
|
|
91
|
+
|
|
92
|
+
Check the following list to see if you're depending on any of these behaviors:
|
|
93
|
+
|
|
94
|
+
1. Puma will now listen on `::` (IPv6) by default. Previously, it listened to `0.0.0.0` (IPv4). Systems that support both IPv6 and IPv4 (Ubuntu and Mac commonly do) will still support receiving to `0.0.0.0`. See [[the support table in the PR](https://github.com/puma/puma/pull/3847)](https://github.com/puma/puma/pull/3847) for a binding compatibility. For systems that ONLY bind to IPv6 (without IPv4 support) this may be a breaking change. You can overwrite this default behavior by setting `bind 'tcp://0.0.0.0:9292'`, `port ENV.fetch('PORT', 9292), '0.0.0.0'`, or `set_default_host '0.0.0.0'` explicitly to remain IPv4 only. Review any firewall rules, health checks, deploy scripts, or host-string parsing code that assumed `0.0.0.0`, `127.0.0.1`, or unbracketed `HOST:PORT` formatting.
|
|
95
|
+
2. If you explicitly configure `bind 'tcp://[::]:...'`, `bind 'ssl://[::]:...'`, or equivalent `ssl_bind '::', ...`, Puma will now rewrite that unspecified IPv6 bind to `0.0.0.0` when the host has no non-loopback IPv6 interface, and it will warn on boot. If you were using `::` to force IPv6-only behavior or to detect IPv6 availability, switch to a concrete IPv6 address instead of `::`, or ensure the machine actually has a usable IPv6 interface before Puma starts.
|
|
96
|
+
3. `before_thread_start` hooks now receive a `Puma::ServerPluginControl` argument. Update any zero-arity lambdas, method objects, or other strict-arity hook code to accept one argument, for example `before_thread_start { |_control| ... }`, or Puma can raise `ArgumentError` when the hook runs.
|
|
97
|
+
4. On platforms without `SIGINFO`, Puma now traps `SIGPWR`, and `pumactl info` sends `SIGPWR` there. If your supervisor, init script, or container tooling already uses `SIGPWR` for something else, change that wiring before upgrading and update any runbooks that assumed Puma would ignore `SIGPWR`.
|
|
98
|
+
5. Requests rejected by `supported_http_methods` are now treated as parser/client errors earlier in request processing. If you use `supported_http_methods`, re-test unsupported-method requests and do not depend on the old 501 timing, connection handling, or `lowlevel_error_handler` behavior; if your error handler still sees these requests, make sure it tolerates a less-normalized Rack `env`.
|
|
99
|
+
6. `http_content_length_limit` enforcement is stricter now. A `413` on an HTTP/1.1 keep-alive request now forces `connection: close`, and chunked request bodies are rejected as soon as they cross the limit during parsing. Update clients, proxies, and tests not to reuse the socket after a `413`, and re-test any upload flows or custom error handling that depended on Puma's previous oversized-body behavior.
|
|
100
|
+
7. If you use `fork_worker`, phased restart order changed. During `USR1` or `pumactl phased-restart`, worker `0` is now reinserted and restarted/reforked first after replacement. Update deployment scripts, canary logic, or monitoring that assumed the old worker sequence or keyed rollout steps off worker index order.
|