puma 3.0.0.rc1 → 5.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/{History.txt → History.md} +703 -70
- data/LICENSE +23 -20
- data/README.md +173 -163
- data/docs/architecture.md +37 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +28 -6
- data/docs/fork_worker.md +31 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +13 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +1 -1
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +38 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +57 -3
- data/docs/systemd.md +228 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +16 -0
- data/ext/puma_http11/http11_parser.c +287 -468
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.java.rl +21 -37
- data/ext/puma_http11/http11_parser.rl +10 -9
- data/ext/puma_http11/http11_parser_common.rl +4 -4
- data/ext/puma_http11/mini_ssl.c +159 -10
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +99 -132
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
- data/ext/puma_http11/puma_http11.c +6 -38
- data/lib/puma.rb +25 -5
- data/lib/puma/accept_nonblock.rb +7 -1
- data/lib/puma/app/status.rb +53 -26
- data/lib/puma/binder.rb +150 -119
- data/lib/puma/cli.rb +56 -38
- data/lib/puma/client.rb +277 -80
- data/lib/puma/cluster.rb +326 -130
- data/lib/puma/commonlogger.rb +21 -20
- data/lib/puma/configuration.rb +160 -161
- data/lib/puma/const.rb +50 -47
- data/lib/puma/control_cli.rb +104 -63
- data/lib/puma/detect.rb +13 -1
- data/lib/puma/dsl.rb +463 -114
- data/lib/puma/events.rb +22 -13
- data/lib/puma/io_buffer.rb +9 -5
- data/lib/puma/jruby_restart.rb +2 -59
- data/lib/puma/launcher.rb +195 -105
- data/lib/puma/minissl.rb +110 -4
- data/lib/puma/minissl/context_builder.rb +76 -0
- data/lib/puma/null_io.rb +9 -14
- data/lib/puma/plugin.rb +32 -12
- data/lib/puma/plugin/tmp_restart.rb +19 -6
- data/lib/puma/rack/builder.rb +7 -5
- data/lib/puma/rack/urlmap.rb +11 -8
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +242 -32
- data/lib/puma/runner.rb +41 -30
- data/lib/puma/server.rb +265 -183
- data/lib/puma/single.rb +22 -63
- data/lib/puma/state_file.rb +9 -2
- data/lib/puma/thread_pool.rb +179 -68
- data/lib/puma/util.rb +3 -11
- data/lib/rack/handler/puma.rb +60 -11
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +1 -2
- metadata +35 -99
- data/COPYING +0 -55
- data/Gemfile +0 -13
- data/Manifest.txt +0 -79
- data/Rakefile +0 -158
- data/docs/config.md +0 -0
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/capistrano.rb +0 -94
- data/lib/puma/compat.rb +0 -18
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_18.rb +0 -56
- data/lib/puma/rack/backports/uri/common_192.rb +0 -52
- data/lib/puma/rack/backports/uri/common_193.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -32
- data/puma.gemspec +0 -52
- data/tools/jungle/README.md +0 -9
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -394
- data/tools/jungle/init.d/run-puma +0 -3
@@ -0,0 +1,37 @@
|
|
1
|
+
# Architecture
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
![http://bit.ly/2iJuFky](images/puma-general-arch.png)
|
6
|
+
|
7
|
+
Puma is a threaded web server, processing requests across a TCP or UNIX socket.
|
8
|
+
|
9
|
+
Workers accept connections from the socket and a thread in the worker's thread pool processes the client's request.
|
10
|
+
|
11
|
+
Clustered mode is shown/discussed here. Single mode is analogous to having a single worker process.
|
12
|
+
|
13
|
+
## Connection pipeline
|
14
|
+
|
15
|
+
![http://bit.ly/2zwzhEK](images/puma-connection-flow.png)
|
16
|
+
|
17
|
+
* Upon startup, Puma listens on a TCP or UNIX socket.
|
18
|
+
* The backlog of this socket is configured (with a default of 1024), determining how many established but unaccepted connections can exist concurrently.
|
19
|
+
* This socket backlog is distinct from the "backlog" of work as reported by the control server stats. The latter is the number of connections in that worker's "todo" set waiting for a worker thread.
|
20
|
+
* By default, a single, separate thread is used to receive HTTP requests across the socket.
|
21
|
+
* When at least one worker thread is available for work, a connection is accepted and placed in this request buffer
|
22
|
+
* This thread waits for entire HTTP requests to be received over the connection
|
23
|
+
* The time spent waiting for the HTTP request body to be received is exposed to the Rack app as `env['puma.request_body_wait']` (milliseconds)
|
24
|
+
* Once received, the connection is pushed into the "todo" set
|
25
|
+
* Worker threads pop work off the "todo" set for processing
|
26
|
+
* The thread processes the request via the rack application (which generates the HTTP response)
|
27
|
+
* The thread writes the response to the connection
|
28
|
+
* Finally, the thread become available to process another connection in the "todo" set
|
29
|
+
|
30
|
+
### Disabling `queue_requests`
|
31
|
+
|
32
|
+
![http://bit.ly/2zxCJ1Z](images/puma-connection-flow-no-reactor.png)
|
33
|
+
|
34
|
+
The `queue_requests` option is `true` by default, enabling the separate thread used to buffer requests as described above.
|
35
|
+
|
36
|
+
If set to `false`, this buffer will not be used for connections while waiting for the request to arrive.
|
37
|
+
In this mode, when a connection is accepted, it is added to the "todo" queue immediately, and a worker will synchronously do any waiting necessary to read the HTTP request from the socket.
|
@@ -27,7 +27,7 @@ Here are some rules of thumb:
|
|
27
27
|
* Use cluster mode and set the number of workers to 1.5x the number of cpu cores
|
28
28
|
in the machine, minimum 2.
|
29
29
|
* Set the number of threads to desired concurrent requests / number of workers.
|
30
|
-
Puma defaults to
|
30
|
+
Puma defaults to 16 and that's a decent number.
|
31
31
|
|
32
32
|
#### Migrating from Unicorn
|
33
33
|
|
@@ -38,23 +38,45 @@ Here are some rules of thumb:
|
|
38
38
|
* As you grow more confident in the thread safety of your app, you can tune the
|
39
39
|
workers down and the threads up.
|
40
40
|
|
41
|
+
#### Ubuntu / Systemd (Systemctl) Installation
|
42
|
+
|
43
|
+
See [systemd.md](systemd.md)
|
44
|
+
|
41
45
|
#### Worker utilization
|
42
46
|
|
43
|
-
**How do you know if you'
|
47
|
+
**How do you know if you've got enough (or too many workers)?**
|
44
48
|
|
45
49
|
A good question. Due to MRI's GIL, only one thread can be executing Ruby code at a time.
|
46
50
|
But since so many apps are waiting on IO from DBs, etc., they can utilize threads
|
47
51
|
to make better use of the process.
|
48
52
|
|
49
53
|
The rule of thumb is you never want processes that are pegged all the time. This
|
50
|
-
means that there is more work to do
|
54
|
+
means that there is more work to do than the process can get through. On the other
|
51
55
|
hand, if you have processes that sit around doing nothing, then they're just eating
|
52
56
|
up resources.
|
53
57
|
|
54
|
-
|
58
|
+
Watch your CPU utilization over time and aim for about 70% on average. This means
|
55
59
|
you've got capacity still but aren't starving threads.
|
56
60
|
|
57
|
-
|
61
|
+
**Measuring utilization**
|
62
|
+
|
63
|
+
Using a timestamp header from an upstream proxy server (eg. nginx or haproxy), it's
|
64
|
+
possible to get an indication of how long requests have been waiting for a Puma
|
65
|
+
thread to become available.
|
66
|
+
|
67
|
+
* Have your upstream proxy set a header with the time it received the request:
|
68
|
+
* nginx: `proxy_set_header X-Request-Start "${msec}";`
|
69
|
+
* haproxy: `http-request set-header X-Request-Start "%t";`
|
70
|
+
* In your Rack middleware, determine the amount of time elapsed since `X-Request-Start`.
|
71
|
+
* To improve accuracy, you will want to subtract time spent waiting for slow clients:
|
72
|
+
* `env['puma.request_body_wait']` contains the number of milliseconds Puma spent
|
73
|
+
waiting for the client to send the request body.
|
74
|
+
* haproxy: `%Th` (TLS handshake time) and `%Ti` (idle time before request) can
|
75
|
+
can also be added as headers.
|
76
|
+
|
77
|
+
## Should I daemonize?
|
78
|
+
|
79
|
+
Daemonization was removed in Puma 5.0. For alternatives, continue reading.
|
58
80
|
|
59
81
|
I prefer to not daemonize my servers and use something like `runit` or `upstart` to
|
60
82
|
monitor them as child processes. This gives them fast response to crashes and
|
@@ -62,7 +84,7 @@ makes it easy to figure out what is going on. Additionally, unlike `unicorn`,
|
|
62
84
|
puma does not require daemonization to do zero-downtime restarts.
|
63
85
|
|
64
86
|
I see people using daemonization because they start puma directly via capistrano
|
65
|
-
task and thus want it to live on past the `cap deploy`. To
|
87
|
+
task and thus want it to live on past the `cap deploy`. To these people I say:
|
66
88
|
You need to be using a process monitor. Nothing is making sure puma stays up in
|
67
89
|
this scenario! You're just waiting for something weird to happen, puma to die,
|
68
90
|
and to get paged at 3am. Do yourself a favor, at least the process monitoring
|
data/docs/fork_worker.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Fork-Worker Cluster Mode [Experimental]
|
2
|
+
|
3
|
+
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:
|
4
|
+
|
5
|
+
```
|
6
|
+
10000 \_ puma 4.3.3 (tcp://0.0.0.0:9292) [puma]
|
7
|
+
10001 \_ puma: cluster worker 0: 10000 [puma]
|
8
|
+
10002 \_ puma: cluster worker 1: 10000 [puma]
|
9
|
+
10003 \_ puma: cluster worker 2: 10000 [puma]
|
10
|
+
10004 \_ puma: cluster worker 3: 10000 [puma]
|
11
|
+
```
|
12
|
+
|
13
|
+
Similar to the `preload_app!` option, the `fork_worker` option allows your application to be initialized only once for copy-on-write memory savings, and it has two additional advantages:
|
14
|
+
|
15
|
+
1. **Compatible with phased restart.** Because the master process itself doesn't preload the application, this mode works with phased restart (`SIGUSR1` or `pumactl phased-restart`). When worker 0 reloads as part of a phased restart, it initializes a new copy of your application first, then the other workers reload by forking from this new worker already containing the new preloaded application.
|
16
|
+
|
17
|
+
This allows a phased restart to complete as quickly as a hot restart (`SIGUSR2` or `pumactl restart`), while still minimizing downtime by staggering the restart across cluster workers.
|
18
|
+
|
19
|
+
2. **'Refork' for additional copy-on-write improvements in running applications.** Fork-worker mode introduces a new `refork` command that re-loads all nonzero workers by re-forking them from worker 0.
|
20
|
+
|
21
|
+
This command can potentially improve memory utilization in large or complex applications that don't fully pre-initialize on startup, because the re-forked workers can share copy-on-write memory with a worker that has been running for a while and serving requests.
|
22
|
+
|
23
|
+
You can trigger a refork by sending the cluster the `SIGURG` signal or running the `pumactl refork` command at any time. A refork will also automatically trigger once, after a certain number of requests have been processed by worker 0 (default 1000). To configure the number of requests before the auto-refork, pass a positive integer argument to `fork_worker` (e.g., `fork_worker 1000`), or `0` to disable.
|
24
|
+
|
25
|
+
### Limitations
|
26
|
+
|
27
|
+
- This mode is still very experimental so there may be bugs or edge-cases, particularly around expected behavior of existing hooks. Please open a [bug report](https://github.com/puma/puma/issues/new?template=bug_report.md) if you encounter any issues.
|
28
|
+
|
29
|
+
- In order to fork new workers cleanly, worker 0 shuts down its server and stops serving requests so there are no open file descriptors or other kinds of shared global state between processes, and to maximize copy-on-write efficiency across the newly-forked workers. This may temporarily reduce total capacity of the cluster during a phased restart / refork.
|
30
|
+
|
31
|
+
In a cluster with `n` workers, a normal phased restart stops and restarts workers one by one while the application is loaded in each process, so `n-1` workers are available serving requests during the restart. In a phased restart in fork-worker mode, the application is first loaded in worker 0 while `n-1` workers are available, then worker 0 remains stopped while the rest of the workers are reloaded one by one, leaving only `n-2` workers to be available for a brief period of time. Reloading the rest of the workers should be quick because the application is preloaded at that point, but there may be situations where it can take longer (slow clients, long-running application code, slow worker-fork hooks, etc).
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Puma as a service
|
2
|
+
|
3
|
+
## Upstart
|
4
|
+
|
5
|
+
See `/docs/jungle/upstart` for Ubuntu's upstart scripts.
|
6
|
+
|
7
|
+
## Systemd
|
8
|
+
|
9
|
+
See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
|
10
|
+
|
11
|
+
## rc.d
|
12
|
+
|
13
|
+
See `/docs/jungle/rc.d` for FreeBSD's rc.d scripts
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Puma as a service using rc.d
|
2
|
+
|
3
|
+
Manage multilpe Puma servers as services on one box using FreeBSD's rc.d service.
|
4
|
+
|
5
|
+
## Dependencies
|
6
|
+
|
7
|
+
* `jq` - a command-line json parser is needed to parse the json in the config file
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
# Copy the puma script to the rc.d directory (make sure everyone has read/execute perms)
|
12
|
+
sudo cp puma /usr/local/etc/rc.d/
|
13
|
+
|
14
|
+
# Create an empty configuration file
|
15
|
+
sudo touch /usr/local/etc/puma.conf
|
16
|
+
|
17
|
+
# Enable the puma service
|
18
|
+
sudo echo 'puma_enable="YES"' >> /etc/rc.conf
|
19
|
+
|
20
|
+
## Managing the jungle
|
21
|
+
|
22
|
+
Puma apps are referenced in /usr/local/etc/puma.conf by default.
|
23
|
+
|
24
|
+
Start the jungle running:
|
25
|
+
|
26
|
+
`service puma start`
|
27
|
+
|
28
|
+
This script will run at boot time.
|
29
|
+
|
30
|
+
|
31
|
+
You can also stop the jungle (stops ALL puma instances) by running:
|
32
|
+
|
33
|
+
`service puma stop`
|
34
|
+
|
35
|
+
|
36
|
+
To restart the jungle:
|
37
|
+
|
38
|
+
`service puma restart`
|
39
|
+
|
40
|
+
## Conventions
|
41
|
+
|
42
|
+
* The script expects:
|
43
|
+
* a config file to exist under `config/puma.rb` in your app. E.g.: `/home/apps/my-app/config/puma.rb`.
|
44
|
+
|
45
|
+
You can always change those defaults by editing the scripts.
|
46
|
+
|
47
|
+
## Here's what a minimal app's config file should have
|
48
|
+
|
49
|
+
```
|
50
|
+
{
|
51
|
+
"servers" : [
|
52
|
+
{
|
53
|
+
"dir": "/path/to/rails/project",
|
54
|
+
"user": "deploy-user",
|
55
|
+
"ruby_version": "ruby.version",
|
56
|
+
"ruby_env": "rbenv"
|
57
|
+
}
|
58
|
+
]
|
59
|
+
}
|
60
|
+
```
|
61
|
+
|
62
|
+
## Before starting...
|
63
|
+
|
64
|
+
You need to customise `puma.conf` to:
|
65
|
+
|
66
|
+
* Set the right user your app should be running on unless you want root to execute it!
|
67
|
+
* Set the directory of the app
|
68
|
+
* Set the ruby version to execute
|
69
|
+
* Set the ruby environment (currently set to rbenv, since that is the only ruby environment currently supported)
|
70
|
+
* Add additional server instances following the scheme in the example
|
71
|
+
|
72
|
+
## Notes:
|
73
|
+
|
74
|
+
Only rbenv is currently supported.
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
|
4
|
+
# PROVIDE: puma
|
5
|
+
|
6
|
+
. /etc/rc.subr
|
7
|
+
|
8
|
+
name="puma"
|
9
|
+
start_cmd="puma_start"
|
10
|
+
stop_cmd="puma_stop"
|
11
|
+
restart_cmd="puma_restart"
|
12
|
+
rcvar=puma_enable
|
13
|
+
required_files=/usr/local/etc/puma.conf
|
14
|
+
|
15
|
+
puma_start()
|
16
|
+
{
|
17
|
+
server_count=$(/usr/local/bin/jq ".servers[] .ruby_env" /usr/local/etc/puma.conf | wc -l)
|
18
|
+
i=0
|
19
|
+
while [ "$i" -lt "$server_count" ]; do
|
20
|
+
rb_env=$(/usr/local/bin/jq -r ".servers[$i].ruby_env" /usr/local/etc/puma.conf)
|
21
|
+
dir=$(/usr/local/bin/jq -r ".servers[$i].dir" /usr/local/etc/puma.conf)
|
22
|
+
user=$(/usr/local/bin/jq -r ".servers[$i].user" /usr/local/etc/puma.conf)
|
23
|
+
rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
|
24
|
+
case $rb_env in
|
25
|
+
"rbenv")
|
26
|
+
su - $user -c "cd $dir && rbenv shell $rb_ver && bundle exec puma -C $dir/config/puma.rb -d"
|
27
|
+
;;
|
28
|
+
*)
|
29
|
+
;;
|
30
|
+
esac
|
31
|
+
i=$(( i + 1 ))
|
32
|
+
done
|
33
|
+
}
|
34
|
+
|
35
|
+
puma_stop()
|
36
|
+
{
|
37
|
+
pkill ruby
|
38
|
+
}
|
39
|
+
|
40
|
+
puma_restart()
|
41
|
+
{
|
42
|
+
server_count=$(/usr/local/bin/jq ".servers[] .ruby_env" /usr/local/etc/puma.conf | wc -l)
|
43
|
+
i=0
|
44
|
+
while [ "$i" -lt "$server_count" ]; do
|
45
|
+
rb_env=$(/usr/local/bin/jq -r ".servers[$i].ruby_env" /usr/local/etc/puma.conf)
|
46
|
+
dir=$(/usr/local/bin/jq -r ".servers[$i].dir" /usr/local/etc/puma.conf)
|
47
|
+
user=$(/usr/local/bin/jq -r ".servers[$i].user" /usr/local/etc/puma.conf)
|
48
|
+
rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
|
49
|
+
case $rb_env in
|
50
|
+
"rbenv")
|
51
|
+
su - $user -c "cd $dir && pkill ruby && rbenv shell $ruby_version && bundle exec puma -C $dir/config/puma.rb -d"
|
52
|
+
;;
|
53
|
+
*)
|
54
|
+
;;
|
55
|
+
esac
|
56
|
+
i=$(( i + 1 ))
|
57
|
+
done
|
58
|
+
}
|
59
|
+
|
60
|
+
load_rc_config $name
|
61
|
+
run_rc_command "$1"
|
File without changes
|
File without changes
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# allows you to manage multiple Puma instances with
|
5
5
|
# Upstart, Ubuntu's native service management tool.
|
6
6
|
#
|
7
|
-
# See
|
7
|
+
# See puma-manager.conf for how to manage all Puma instances at once.
|
8
8
|
#
|
9
9
|
# Save this config as /etc/init/puma.conf then manage puma with:
|
10
10
|
# sudo start puma app=PATH_TO_APP
|
data/docs/nginx.md
CHANGED
@@ -34,7 +34,7 @@ server {
|
|
34
34
|
proxy_set_header Host $http_host;
|
35
35
|
|
36
36
|
# If the file exists as a static file serve it directly without
|
37
|
-
# running all the other
|
37
|
+
# running all the other rewrite tests on it
|
38
38
|
if (-f $request_filename) {
|
39
39
|
break;
|
40
40
|
}
|
@@ -50,7 +50,7 @@ server {
|
|
50
50
|
# this is the meat of the rack page caching config
|
51
51
|
# it adds .html to the end of the url and then checks
|
52
52
|
# the filesystem for that file. If it exists, then we
|
53
|
-
#
|
53
|
+
# rewrite the url to have explicit .html on the end
|
54
54
|
# and then send it on its way to the next config rule.
|
55
55
|
# if there is no file on the fs then it sets all the
|
56
56
|
# necessary headers and proxies to our upstream pumas
|
data/docs/plugins.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
## Plugins
|
2
|
+
|
3
|
+
Puma 3.0 added support for plugins that can augment configuration and service
|
4
|
+
operations.
|
5
|
+
|
6
|
+
2 canonical plugins to look to aid in development of further plugins:
|
7
|
+
|
8
|
+
* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
|
9
|
+
Restarts the server if the file `tmp/restart.txt` is touched
|
10
|
+
* [heroku](https://github.com/puma/puma-heroku/blob/master/lib/puma/plugin/heroku.rb):
|
11
|
+
Packages up the default configuration used by puma on Heroku
|
12
|
+
|
13
|
+
Plugins are activated in a puma configuration file (such as `config/puma.rb'`)
|
14
|
+
by adding `plugin "name"`, such as `plugin "heroku"`.
|
15
|
+
|
16
|
+
Plugins are activated based simply on path requirements so, activating the
|
17
|
+
`heroku` plugin will simply be doing `require "puma/plugin/heroku"`. This
|
18
|
+
allows gems to provide multiple plugins (as well as unrelated gems to provide
|
19
|
+
puma plugins).
|
20
|
+
|
21
|
+
The `tmp_restart` plugin is bundled with puma, so it can always be used.
|
22
|
+
|
23
|
+
To use the `heroku` plugin, add `puma-heroku` to your Gemfile or install it.
|
24
|
+
|
25
|
+
### API
|
26
|
+
|
27
|
+
## Server-wide hooks
|
28
|
+
|
29
|
+
Plugins can use a couple of hooks at server level: `start` and `config`.
|
30
|
+
|
31
|
+
`start` runs when the server has started and allows the plugin to start other
|
32
|
+
functionality to augment puma.
|
33
|
+
|
34
|
+
`config` runs when the server is being configured and is passed a `Puma::DSL`
|
35
|
+
object that can be used to add additional configuration.
|
36
|
+
|
37
|
+
Any public methods in `Puma::Plugin` are the public API that any plugin may
|
38
|
+
use.
|
data/docs/restart.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Restarts
|
2
|
+
|
3
|
+
To perform a restart, there are 3 builtin mechanisms:
|
4
|
+
|
5
|
+
* Send the `puma` process the `SIGUSR2` signal (normal restart)
|
6
|
+
* Send the `puma` process the `SIGUSR1` signal (restart in phases (a "rolling restart"), cluster mode only)
|
7
|
+
* Use the status server and issue `/restart`
|
8
|
+
|
9
|
+
No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop Puma and start it again.
|
10
|
+
|
11
|
+
If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor (see below) when using it in production.
|
12
|
+
|
13
|
+
### Normal vs Hot vs Phased Restart
|
14
|
+
|
15
|
+
A hot restart means that no requests will be lost while deploying your new code, since the server socket is kept open between restarts.
|
16
|
+
|
17
|
+
But beware, hot restart does not mean that the incoming requests won’t hang for multiple seconds while your new code has not fully deployed. If you need a zero downtime and zero hanging requests deploy, you must use phased restart.
|
18
|
+
|
19
|
+
When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that at least another worker is still available to serve requests, which lead to zero hanging requests (yay!).
|
20
|
+
|
21
|
+
But again beware, upgrading an application sometimes involves upgrading the database schema. With phased restart, there may be a moment during the deployment where processes belonging to the previous version and processes belonging to the new version both exist at the same time. Any database schema upgrades you perform must therefore be backwards-compatible with the old application version.
|
22
|
+
|
23
|
+
If you perform a lot of database migrations, you probably should not use phased restart and use a normal/hot restart instead (`pumactl restart`). That way, no code is shared while deploying (in that case, `preload_app!` might help for quicker deployment, see ["Clustered Mode" in the README](../README.md#clustered-mode)).
|
24
|
+
|
25
|
+
**Note**: Hot and phased restarts are only available on MRI, not on JRuby. They are also unavailable on Windows servers.
|
26
|
+
|
27
|
+
### Release Directory
|
28
|
+
|
29
|
+
If your symlink releases into a common working directory (i.e., `/current` from Capistrano), Puma won't pick up your new changes when running phased restarts without additional configuration. You should set your working directory within Puma's config to specify the directory it should use. This is a change from earlier versions of Puma (< 2.15) that would infer the directory for you.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# config/puma.rb
|
33
|
+
|
34
|
+
directory '/var/www/current'
|
35
|
+
```
|
36
|
+
|
37
|
+
### Cleanup Code
|
38
|
+
|
39
|
+
Puma isn't able to understand all the resources that your app may use, so it provides a hook in the configuration file you pass to `-C` called `on_restart`. The block passed to `on_restart` will be called, unsurprisingly, just before Puma restarts itself.
|
40
|
+
|
41
|
+
You should place code to close global log files, redis connections, etc. in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restarted many times.
|
data/docs/signals.md
CHANGED
@@ -36,8 +36,62 @@ Puma cluster responds to these signals:
|
|
36
36
|
- `TTIN` increment the worker count by 1
|
37
37
|
- `TTOU` decrement the worker count by 1
|
38
38
|
- `TERM` send `TERM` to worker. Worker will attempt to finish then exit.
|
39
|
-
- `USR2` restart workers
|
40
|
-
- `USR1` restart workers in phases, a rolling restart.
|
41
|
-
- `HUP` reopen log files defined in stdout_redirect configuration parameter
|
39
|
+
- `USR2` restart workers. This also reloads puma configuration file, if there is one.
|
40
|
+
- `USR1` restart workers in phases, a rolling restart. This will not reload configuration file.
|
41
|
+
- `HUP` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided it will behave like `INT`
|
42
42
|
- `INT` equivalent of sending Ctrl-C to cluster. Will attempt to finish then exit.
|
43
43
|
- `CHLD`
|
44
|
+
- `URG` refork workers in phases from worker 0, if `fork_workers` option is enabled.
|
45
|
+
|
46
|
+
## Callbacks order in case of different signals
|
47
|
+
|
48
|
+
### Start application
|
49
|
+
|
50
|
+
```
|
51
|
+
puma configuration file reloaded, if there is one
|
52
|
+
* Pruning Bundler environment
|
53
|
+
puma configuration file reloaded, if there is one
|
54
|
+
|
55
|
+
before_fork
|
56
|
+
on_worker_fork
|
57
|
+
after_worker_fork
|
58
|
+
|
59
|
+
Gemfile in context
|
60
|
+
|
61
|
+
on_worker_boot
|
62
|
+
|
63
|
+
Code of the app is loaded and running
|
64
|
+
```
|
65
|
+
|
66
|
+
### Send USR2
|
67
|
+
|
68
|
+
```
|
69
|
+
on_worker_shutdown
|
70
|
+
on_restart
|
71
|
+
|
72
|
+
puma configuration file reloaded, if there is one
|
73
|
+
|
74
|
+
before_fork
|
75
|
+
on_worker_fork
|
76
|
+
after_worker_fork
|
77
|
+
|
78
|
+
Gemfile in context
|
79
|
+
|
80
|
+
on_worker_boot
|
81
|
+
|
82
|
+
Code of the app is loaded and running
|
83
|
+
```
|
84
|
+
|
85
|
+
### Send USR1
|
86
|
+
|
87
|
+
```
|
88
|
+
on_worker_shutdown
|
89
|
+
on_worker_fork
|
90
|
+
after_worker_fork
|
91
|
+
|
92
|
+
Gemfile in context
|
93
|
+
|
94
|
+
on_worker_boot
|
95
|
+
|
96
|
+
Code of the app is loaded and running
|
97
|
+
```
|