pitchfork 0.16.0 → 0.17.0
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/.github/workflows/ci.yml +8 -2
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -1
- data/README.md +12 -12
- data/Rakefile +14 -25
- data/docs/CONFIGURATION.md +36 -13
- data/docs/DESIGN.md +7 -7
- data/docs/FORK_SAFETY.md +3 -0
- data/docs/PHILOSOPHY.md +2 -2
- data/docs/REFORKING.md +12 -12
- data/docs/SIGNALS.md +7 -8
- data/docs/TUNING.md +3 -3
- data/examples/nginx.conf +1 -1
- data/examples/pitchfork.conf.rb +1 -1
- data/ext/pitchfork_http/c_util.h +2 -2
- data/ext/pitchfork_http/epollexclusive.h +2 -2
- data/lib/pitchfork/children.rb +1 -1
- data/lib/pitchfork/configurator.rb +13 -12
- data/lib/pitchfork/http_server.rb +64 -60
- data/lib/pitchfork/info.rb +3 -2
- data/lib/pitchfork/refork_condition.rb +1 -1
- data/lib/pitchfork/shared_memory.rb +36 -9
- data/lib/pitchfork/version.rb +1 -1
- data/lib/pitchfork/worker.rb +57 -34
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b22167ab418be7e6f7ad8a8c66177582b80e611423531f7f96f132688f684c8d
|
4
|
+
data.tar.gz: 036fbed35ccdece6c17b26f0f4011b78efcc33e4344e6fbe94fcb5ee170d52d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd7bd9b5ef42730eb970b368d18fc188834e65a8a7104666cf320d6ef71e629196dbab2ef081a11c988b5232de9084d7debe732ee306524dc503d7464f33823f
|
7
|
+
data.tar.gz: 53db8ad62bfdd0e21d8e01734427a9cc59a3594438b61616a2c0151dc563d5d2bc84521b1085ba797821598a8d35c9f95db12d50c3a909dfe03bc7834404c49b
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
---
|
2
2
|
name: Test
|
3
|
-
|
3
|
+
|
4
|
+
on:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
|
9
|
+
pull_request:
|
4
10
|
|
5
11
|
jobs:
|
6
12
|
ruby:
|
@@ -24,7 +30,7 @@ jobs:
|
|
24
30
|
env:
|
25
31
|
RACK_VERSION: "${{ matrix.rack }}"
|
26
32
|
RUBYOPT: "${{ matrix.rubyopt }}"
|
27
|
-
runs-on: ubuntu-
|
33
|
+
runs-on: ubuntu-22.04
|
28
34
|
steps:
|
29
35
|
- name: Check out code
|
30
36
|
uses: actions/checkout@v4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 0.17.0
|
4
|
+
|
5
|
+
- Improve `Pitchfork::Info#live_workers_count` to be more accurate.
|
6
|
+
- Refactor all server logs to be more consistent.
|
7
|
+
- Add `setpgid` configuration option. When `false`, child processes are not reassigned to their own process group.
|
8
|
+
Necessary for initiating a debugging session in a child process (#148).
|
9
|
+
- Assume config file is located at `config/pitchfork.rb` if `-c` argument isn't provided.
|
10
|
+
- Remove `Pitchfork::Configurator#after_load` and `Pitchfork::Configurator#after_load=`, which have had no function since v0.1.0.
|
11
|
+
- Fix a race condition triggered by a shutdown happening concurrently with a new mold initialization.
|
12
|
+
|
3
13
|
# 0.16.0
|
4
14
|
|
5
15
|
- Use `exit!` for exiting the middle process when forking a new worker or mold.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -18,10 +18,10 @@ both the request and response in between `pitchfork` and slow clients.
|
|
18
18
|
* Shared-Nothing architecture: workers all run within their own isolated
|
19
19
|
address space and only serve one client at a time for maximum performance
|
20
20
|
and robustness. Concurrent requests don't need to compete for the GVL,
|
21
|
-
or impact each
|
21
|
+
or impact each other's latency when triggering garbage collection.
|
22
22
|
It also does not care if your application is thread-safe or not.
|
23
23
|
|
24
|
-
* Reforking: `pitchfork` can be configured to periodically promote a warmed
|
24
|
+
* Reforking: `pitchfork` can be configured to periodically promote a warmed-up worker
|
25
25
|
as the new template from which workers are forked. This dramatically improves
|
26
26
|
the proportion of shared memory, making processes use only marginally more
|
27
27
|
memory than threads would.
|
@@ -31,10 +31,10 @@ both the request and response in between `pitchfork` and slow clients.
|
|
31
31
|
* Process management: `pitchfork` will reap and restart workers that
|
32
32
|
die from broken apps. There is no need to manage multiple processes
|
33
33
|
or ports yourself. `pitchfork` can spawn and manage any number of
|
34
|
-
worker processes you choose to scale
|
34
|
+
worker processes you choose to scale your backend to.
|
35
35
|
|
36
|
-
* Adaptative timeout: request
|
37
|
-
per
|
36
|
+
* Adaptative timeout: request timeouts can be extended dynamically on a
|
37
|
+
per-request basis, which allows you to keep a strict overall timeout for
|
38
38
|
most endpoints, but allow a few endpoints to take longer.
|
39
39
|
|
40
40
|
* Load balancing is done entirely by the operating system kernel.
|
@@ -42,8 +42,8 @@ both the request and response in between `pitchfork` and slow clients.
|
|
42
42
|
|
43
43
|
## When to Use
|
44
44
|
|
45
|
-
Pitchfork isn't inherently better than other Ruby application servers
|
46
|
-
|
45
|
+
Pitchfork isn't inherently better than other Ruby application servers; it mostly
|
46
|
+
focuses on different tradeoffs.
|
47
47
|
|
48
48
|
If you are fine with your current server, it's best to stick with it.
|
49
49
|
|
@@ -52,7 +52,7 @@ If there is a problem you are trying to solve, please read the
|
|
52
52
|
|
53
53
|
## Requirements
|
54
54
|
|
55
|
-
Ruby(MRI) Version 2.5
|
55
|
+
Ruby(MRI) Version 2.5 or above.
|
56
56
|
|
57
57
|
`pitchfork` can be used on any Unix-like system, however the reforking
|
58
58
|
feature requires `PR_SET_CHILD_SUBREAPER` which is a Linux 3.4 (May 2012) feature.
|
@@ -93,7 +93,7 @@ address:port or a UNIX socket.
|
|
93
93
|
|
94
94
|
### Configuration File(s)
|
95
95
|
|
96
|
-
`pitchfork` will look for the config.ru file used by rackup in APP_ROOT
|
96
|
+
`pitchfork` will look for the config.ru file used by rackup in `APP_ROOT`.
|
97
97
|
|
98
98
|
For deployments, it can use a config file for pitchfork-specific options
|
99
99
|
specified by the `--config-file/-c` command-line switch.
|
@@ -108,8 +108,8 @@ supported. Run `pitchfork -h` to see command-line options.
|
|
108
108
|
|
109
109
|
## Relation to Unicorn
|
110
110
|
|
111
|
-
Pitchfork initially started as a Unicorn patch, however some
|
112
|
-
as well as Unicorn policy of supporting extremely old Ruby version made it challenging.
|
111
|
+
Pitchfork initially started as a Unicorn patch, however some Unicorn features
|
112
|
+
as well as the Unicorn policy of supporting extremely old Ruby version made it challenging.
|
113
113
|
|
114
114
|
Forking was the occasion to significantly reduce the complexity.
|
115
115
|
|
@@ -134,6 +134,6 @@ Thanks to Eric Wong and all Unicorn and Mongrel contributors over the years.
|
|
134
134
|
Pitchfork would have been much harder to implement otherwise.
|
135
135
|
|
136
136
|
Thanks to Will Jordan who implemented Puma's "fork worker" experimental feature
|
137
|
-
which
|
137
|
+
which has been a significant inspiration for Pitchfork.
|
138
138
|
|
139
139
|
Thanks to Peter Bui for letting us use the `pitchfork` name on Rubygems.
|
data/Rakefile
CHANGED
@@ -1,39 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "bundler/gem_tasks"
|
3
|
-
require "rake/testtask"
|
4
3
|
require "rake/extensiontask"
|
5
4
|
|
6
|
-
|
7
|
-
t.libs << "test"
|
8
|
-
t.libs << "lib"
|
9
|
-
t.test_files = FileList["test/unit/**/test_*.rb"]
|
10
|
-
t.options = '-v' if ENV['CI'] || ENV['VERBOSE']
|
11
|
-
t.warning = true
|
12
|
-
end
|
13
|
-
|
14
|
-
Rake::TestTask.new("test:integration") do |t|
|
15
|
-
t.libs << "test"
|
16
|
-
t.libs << "lib"
|
17
|
-
t.test_files = FileList["test/integration/**/test_*.rb"]
|
18
|
-
t.options = '-v' if ENV['CI'] || ENV['VERBOSE']
|
19
|
-
t.warning = true
|
20
|
-
end
|
5
|
+
require "megatest/test_task"
|
21
6
|
|
22
7
|
namespace :test do
|
8
|
+
Megatest::TestTask.create(:unit) do |t|
|
9
|
+
t.tests = FileList["test/unit/**/test_*.rb"]
|
10
|
+
t.deps << :compile
|
11
|
+
end
|
12
|
+
|
13
|
+
Megatest::TestTask.create(:integration) do |t|
|
14
|
+
t.tests = FileList["test/integration/**/test_*.rb"]
|
15
|
+
t.deps << :compile
|
16
|
+
end
|
17
|
+
|
23
18
|
# It's not so much that these tests are slow, but they tend to fork
|
24
19
|
# and/or register signal handlers, so they if something goes wrong
|
25
20
|
# they are likely to get stuck forever.
|
26
21
|
# The unicorn test suite has historically ran them in individual process
|
27
22
|
# so we continue to do that.
|
28
|
-
|
29
|
-
tests =
|
30
|
-
|
31
|
-
[test_file] + test
|
32
|
-
end
|
33
|
-
end
|
34
|
-
tests.each do |file, test|
|
35
|
-
sh "ruby", "-Ilib:test", file, "-n", test, "-v"
|
36
|
-
end
|
23
|
+
Megatest::TestTask.create(:slow) do |t|
|
24
|
+
t.tests = FileList["test/slow/**/test_*.rb"]
|
25
|
+
t.deps << :compile
|
37
26
|
end
|
38
27
|
|
39
28
|
# Unicorn had its own POSIX-shell based testing framework.
|
data/docs/CONFIGURATION.md
CHANGED
@@ -16,7 +16,7 @@ Each worker process will serve exactly one client at a time.
|
|
16
16
|
|
17
17
|
### `listen`
|
18
18
|
|
19
|
-
By default
|
19
|
+
By default Pitchfork listens to port 8080.
|
20
20
|
|
21
21
|
```ruby
|
22
22
|
listen 2007
|
@@ -25,19 +25,20 @@ listen 8080, tcp_nopush: true
|
|
25
25
|
```
|
26
26
|
|
27
27
|
Adds an address to the existing listener set. May be specified more
|
28
|
-
than once. address may be an Integer port number for a TCP port, an
|
28
|
+
than once. The address may be an Integer port number for a TCP port, an
|
29
29
|
`IP_ADDRESS:PORT` for TCP listeners or a pathname for UNIX domain sockets.
|
30
30
|
|
31
31
|
```ruby
|
32
32
|
listen 3000 # listen to port 3000 on all TCP interfaces
|
33
|
-
listen "127.0.0.1:3000"
|
33
|
+
listen "127.0.0.1:3000" # listen to port 3000 on the loopback interface
|
34
34
|
listen "/path/to/.pitchfork.sock" # listen on the given Unix domain socket
|
35
35
|
listen "[::1]:3000" # listen to port 3000 on the IPv6 loopback interface
|
36
36
|
```
|
37
37
|
|
38
38
|
When using Unix domain sockets, be sure:
|
39
39
|
1) the path matches the one used by nginx
|
40
|
-
2)
|
40
|
+
2) to use the same filesystem namespace as the nginx process
|
41
|
+
|
41
42
|
For systemd users using PrivateTmp=true (for either nginx or pitchfork),
|
42
43
|
this means Unix domain sockets must not be placed in /tmp
|
43
44
|
|
@@ -152,7 +153,7 @@ The following options may be specified (but are generally not needed):
|
|
152
153
|
disproportionally more requests than workers with higher PID.
|
153
154
|
It generally isn't a problem, especially when reforking is enabled, but for
|
154
155
|
applications that are routinely over provisioned, it may be desirable to
|
155
|
-
ensure all workers at least get some incoming requests so
|
156
|
+
ensure all workers at least get some incoming requests so they can warm up.
|
156
157
|
|
157
158
|
Creating more than one queue allow to restrict which worker can process
|
158
159
|
a given incomming request, hence making the load balancing fairer.
|
@@ -168,6 +169,18 @@ The following options may be specified (but are generally not needed):
|
|
168
169
|
|
169
170
|
Default: `queues - 1`.
|
170
171
|
|
172
|
+
- `setpgid: true or false`
|
173
|
+
|
174
|
+
When enabled, child processes will be made into a group leader with a pgid matching
|
175
|
+
their pid. The child process will no longer be in the foreground process group of
|
176
|
+
its control terminal.
|
177
|
+
|
178
|
+
This can break debugging sessions and interactive terminals inside the worker
|
179
|
+
processes. Set it to `false` if you need to activate a debugging session or read from
|
180
|
+
`STDIN` inside a worker process.
|
181
|
+
|
182
|
+
Default: `true` (enabled)
|
183
|
+
|
171
184
|
- `umask: mode`
|
172
185
|
|
173
186
|
Sets the file mode creation mask for UNIX sockets.
|
@@ -251,7 +264,7 @@ Due the low-complexity, low-overhead implementation, timeouts of less
|
|
251
264
|
than 3.0 seconds can be considered inaccurate and unsafe.
|
252
265
|
|
253
266
|
For running Pitchfork behind nginx, it is recommended to set
|
254
|
-
"fail_timeout=0"
|
267
|
+
"fail_timeout=0" in your nginx configuration like this
|
255
268
|
to have nginx always retry backends that may have had workers
|
256
269
|
exit or be SIGKILL-ed due to timeouts.
|
257
270
|
|
@@ -295,14 +308,14 @@ The default Logger will log its output to STDERR.
|
|
295
308
|
|
296
309
|
## Callbacks
|
297
310
|
|
298
|
-
|
311
|
+
Pitchfork provides several callbacks hooks around the lifecycle of workers.
|
299
312
|
It is often necessary to use these callbacks to close inherited connection after fork.
|
300
313
|
|
301
|
-
Note that when reforking is available, the
|
314
|
+
Note that when reforking is available, the Pitchfork monitor process won't load your application
|
302
315
|
at all. As such for hooks executed in the monitor, you may need to explicitly load the parts of your
|
303
316
|
application that are used in hooks.
|
304
317
|
|
305
|
-
|
318
|
+
Pitchfork also doesn't attempt to rescue hook errors. Raising from a worker hook will crash the worker,
|
306
319
|
and raising from a monitor hook will bring the whole cluster down.
|
307
320
|
|
308
321
|
### `after_monitor_ready`
|
@@ -312,13 +325,13 @@ spawning the original workers.
|
|
312
325
|
|
313
326
|
```ruby
|
314
327
|
after_monitor_ready do |server|
|
315
|
-
server.logger.info("
|
328
|
+
server.logger.info("monitor pid=#{Process.pid} ready")
|
316
329
|
end
|
317
330
|
```
|
318
331
|
|
319
332
|
### `before_fork`
|
320
333
|
|
321
|
-
Called by the mold before forking
|
334
|
+
Called by the mold before forking new workers, and by workers before they spawn a new mold.
|
322
335
|
|
323
336
|
```ruby
|
324
337
|
before_fork do |server|
|
@@ -417,16 +430,26 @@ By default the cleanup timeout is 2 seconds.
|
|
417
430
|
Called in the monitor process when a worker hard timeout is elapsed:
|
418
431
|
|
419
432
|
```ruby
|
420
|
-
|
433
|
+
after_worker_hard_timeout do |server, worker|
|
421
434
|
$stderr.puts "Worker hard timeout, pid=#{worker.pid}"
|
422
435
|
end
|
423
436
|
```
|
424
437
|
|
425
438
|
Once the callback complete, the worker will be signaled with `SIGKILL`.
|
426
439
|
|
427
|
-
This callback being called
|
440
|
+
This callback being called is an indication that something is preventing the
|
428
441
|
soft timeout from working.
|
429
442
|
|
443
|
+
### `before_worker_exit`
|
444
|
+
|
445
|
+
Called in the worker process before it is shut down.
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
before_worker_exit do |server, worker|
|
449
|
+
server.logger.info("worker=#{worker.nr} shuts down after #{worker.requests_count} requests")
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
430
453
|
### `after_worker_exit`
|
431
454
|
|
432
455
|
Called in the monitor process after a worker exits.
|
data/docs/DESIGN.md
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
* Simplicity: Pitchfork is a traditional UNIX prefork web server.
|
4
4
|
No threads are used at all, this makes applications easier to debug
|
5
5
|
and fix.
|
6
|
-
|
7
|
-
* Resiliency: If something
|
8
|
-
is dead locked or somehow stuck, once the request timeout is reached the
|
6
|
+
|
7
|
+
* Resiliency: If something goes catastrophically wrong and your application
|
8
|
+
is dead locked or somehow stuck, once the request timeout is reached the monitor
|
9
9
|
process will take care of sending `kill -9` to the affected worker and
|
10
10
|
spawn a new one to replace it.
|
11
11
|
|
@@ -32,7 +32,7 @@
|
|
32
32
|
optional, separate config_file may be used to modify supported
|
33
33
|
configuration changes.
|
34
34
|
|
35
|
-
* One
|
35
|
+
* One monitor process spawns and reaps worker processes.
|
36
36
|
|
37
37
|
* The number of worker processes should be scaled to the number of
|
38
38
|
CPUs or memory you have. If you have an existing
|
@@ -75,12 +75,12 @@
|
|
75
75
|
unportable event notification solutions for watching few
|
76
76
|
file descriptors.
|
77
77
|
|
78
|
-
* If the
|
78
|
+
* If the monitor process dies unexpectedly for any reason,
|
79
79
|
workers will notice within :timeout/2 seconds and follow
|
80
|
-
the
|
80
|
+
the monitor to its death.
|
81
81
|
|
82
82
|
* There is never any explicit real-time dependency or communication
|
83
|
-
between the worker processes nor to the
|
83
|
+
between the worker processes nor to the monitor process.
|
84
84
|
Synchronization is handled entirely by the OS kernel and shared
|
85
85
|
resources are never accessed by the worker when it is servicing
|
86
86
|
a client.
|
data/docs/FORK_SAFETY.md
CHANGED
@@ -91,4 +91,7 @@ impact of discovering such bug.
|
|
91
91
|
|
92
92
|
- Any gem binding with `libgobject`, such as the `gda` gem, likely aren't fork safe.
|
93
93
|
|
94
|
+
- If you use `jemalloc`, [the version `5.2` is known to have a fork safety bug that can cause childs to lock up](https://github.com/jemalloc/jemalloc/issues/2019).
|
95
|
+
Make sure to upgrade to version `5.3`.
|
96
|
+
|
94
97
|
No other gem is known to be incompatible for now, but if you find one, please open an issue to add it to the list.
|
data/docs/PHILOSOPHY.md
CHANGED
@@ -34,7 +34,7 @@ the right tool with the right configuration for the right job.
|
|
34
34
|
|
35
35
|
## Improved Performance Through Reverse Proxying
|
36
36
|
|
37
|
-
By acting as a buffer to shield
|
37
|
+
By acting as a buffer to shield `pitchfork` from slow I/O, a reverse proxy
|
38
38
|
will inevitably incur overhead in the form of extra data copies.
|
39
39
|
However, as I/O within a local network is fast (and faster still
|
40
40
|
with local sockets), this overhead is negligible for the vast majority
|
@@ -45,7 +45,7 @@ A reverse proxy for `pitchfork` should meet the following requirements:
|
|
45
45
|
|
46
46
|
1. It should fully buffer all HTTP requests (and large responses).
|
47
47
|
Each request should be "corked" in the reverse proxy and sent
|
48
|
-
as fast as possible to the backend
|
48
|
+
as fast as possible to the backend `pitchfork` processes. This is
|
49
49
|
the most important feature to look for when choosing a
|
50
50
|
reverse proxy for `pitchfork`.
|
51
51
|
|
data/docs/REFORKING.md
CHANGED
@@ -50,15 +50,15 @@ When you start `pitchfork` it forks a `mold` process which loads your applicatio
|
|
50
50
|
|
51
51
|
```
|
52
52
|
PID COMMAND
|
53
|
-
100 \_ pitchfork
|
53
|
+
100 \_ pitchfork monitor
|
54
54
|
101 \_ pitchfork (gen:0) mold
|
55
55
|
```
|
56
56
|
|
57
|
-
Once the `mold` is done loading, the `
|
57
|
+
Once the `mold` is done loading, the `monitor` asks it to spawn the desired number of workers:
|
58
58
|
|
59
59
|
```
|
60
60
|
PID COMMAND
|
61
|
-
100 \_ pitchfork
|
61
|
+
100 \_ pitchfork monitor
|
62
62
|
101 \_ pitchfork (gen:0) mold
|
63
63
|
102 \_ pitchfork (gen:0) worker[0]
|
64
64
|
103 \_ pitchfork (gen:0) worker[1]
|
@@ -66,14 +66,14 @@ PID COMMAND
|
|
66
66
|
105 \_ pitchfork (gen:0) worker[3]
|
67
67
|
```
|
68
68
|
|
69
|
-
As the diagram shows, while workers are forked from the mold, they become children of the
|
69
|
+
As the diagram shows, while workers are forked from the mold, they become children of the monitor process.
|
70
70
|
We'll see how does that work [later](#forking-sibling-processes).
|
71
71
|
|
72
72
|
When a reforking is triggered, one of the workers is selected to fork a new `mold`:
|
73
73
|
|
74
74
|
```
|
75
75
|
PID COMMAND
|
76
|
-
100 \_ pitchfork
|
76
|
+
100 \_ pitchfork monitor
|
77
77
|
101 \_ pitchfork (gen:0) mold
|
78
78
|
102 \_ pitchfork (gen:0) worker[0]
|
79
79
|
103 \_ pitchfork (gen:0) worker[1]
|
@@ -82,7 +82,7 @@ PID COMMAND
|
|
82
82
|
105 \_ pitchfork (gen:1) mold
|
83
83
|
```
|
84
84
|
|
85
|
-
Again, while the mold was forked from a worker, it becomes a child of the
|
85
|
+
Again, while the mold was forked from a worker, it becomes a child of the monitor process.
|
86
86
|
We'll see how does that work [later](#forking-sibling-processes).
|
87
87
|
|
88
88
|
When that new mold is ready, `pitchfork` terminates the old mold and starts a slow rollout of older workers and replace them with fresh workers
|
@@ -90,7 +90,7 @@ forked from the mold:
|
|
90
90
|
|
91
91
|
```
|
92
92
|
PID COMMAND
|
93
|
-
100 \_ pitchfork
|
93
|
+
100 \_ pitchfork monitor
|
94
94
|
102 \_ pitchfork (gen:0) worker[0]
|
95
95
|
103 \_ pitchfork (gen:0) worker[1]
|
96
96
|
104 \_ pitchfork (gen:0) worker[2]
|
@@ -100,7 +100,7 @@ PID COMMAND
|
|
100
100
|
|
101
101
|
```
|
102
102
|
PID COMMAND
|
103
|
-
100 \_ pitchfork
|
103
|
+
100 \_ pitchfork monitor
|
104
104
|
103 \_ pitchfork (gen:0) worker[1]
|
105
105
|
104 \_ pitchfork (gen:0) worker[2]
|
106
106
|
105 \_ pitchfork (gen:0) worker[3]
|
@@ -117,15 +117,15 @@ a process tree such as:
|
|
117
117
|
|
118
118
|
```
|
119
119
|
PID COMMAND
|
120
|
-
100 \_ pitchfork
|
120
|
+
100 \_ pitchfork monitor
|
121
121
|
101 \_ pitchfork mold (gen:1)
|
122
122
|
105 \_ pitchfork (gen:1) worker[0]
|
123
123
|
```
|
124
124
|
|
125
|
-
However the `pitchfork`
|
126
|
-
This means that any descendant process that is orphaned will be re-parented as a child of the
|
125
|
+
However the `pitchfork` monitor process registers itself as a "child subreaper" via [`PR_SET_CHILD_SUBREAPER`](https://man7.org/linux/man-pages/man2/prctl.2.html).
|
126
|
+
This means that any descendant process that is orphaned will be re-parented as a child of the monitor process rather than a child of the init process (pid 1).
|
127
127
|
|
128
|
-
With this in mind, the mold forks twice to create an orphaned process that will get re-attached to the
|
128
|
+
With this in mind, the mold forks twice to create an orphaned process that will get re-attached to the monitor process,
|
129
129
|
effectively forking a sibling rather than a child. Similarly, workers do the same when forking new molds.
|
130
130
|
This technique eases killing previous generations of molds and workers.
|
131
131
|
|
data/docs/SIGNALS.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
## Signal handling
|
2
2
|
|
3
|
-
In general, signals need to only be sent to the
|
3
|
+
In general, signals need to only be sent to the monitor process. However,
|
4
4
|
the signals Pitchfork uses internally to communicate with the worker
|
5
5
|
processes are documented here as well.
|
6
6
|
|
7
|
-
###
|
7
|
+
### Monitor Process
|
8
8
|
|
9
9
|
* `INT` - quick shutdown, kills all workers immediately
|
10
10
|
|
@@ -21,18 +21,17 @@ processes are documented here as well.
|
|
21
21
|
|
22
22
|
### Worker Processes
|
23
23
|
|
24
|
-
Note: the
|
24
|
+
Note: the monitor uses a pipe to signal workers
|
25
25
|
instead of `kill(2)` for most cases. Using signals still works and
|
26
26
|
remains supported for external tools/libraries, however.
|
27
27
|
|
28
28
|
Sending signals directly to the worker processes should not normally be
|
29
|
-
needed. If the
|
29
|
+
needed. If the monitor process is running, any exited worker will be
|
30
30
|
automatically respawned.
|
31
31
|
|
32
32
|
* `INT` - Quick shutdown, immediately exit.
|
33
|
-
The
|
34
|
-
Immediate shutdown is
|
35
|
-
internal pipe as of unicorn 4.8
|
33
|
+
The monitor process will respawn a worker to replace this one.
|
34
|
+
Immediate shutdown is triggered using kill(2).
|
36
35
|
|
37
36
|
* `QUIT/TERM` - Gracefully exit after finishing the current request.
|
38
|
-
The
|
37
|
+
The monitor process will respawn a worker to replace this one.
|
data/docs/TUNING.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Tuning pitchfork
|
2
2
|
|
3
|
-
|
3
|
+
Pitchfork performance is generally as good as a (mostly) Ruby web server
|
4
4
|
can provide. Most often the performance bottleneck is in the web
|
5
5
|
application running on Pitchfork rather than Pitchfork itself.
|
6
6
|
|
@@ -14,7 +14,7 @@ See Pitchfork::Configurator for details on the config file format.
|
|
14
14
|
* `worker_processes` should be scaled to the number of processes your
|
15
15
|
backend system(s) can support. DO NOT scale it to the number of
|
16
16
|
external network clients your application expects to be serving.
|
17
|
-
|
17
|
+
Pitchfork is NOT for serving slow clients, that is the job of nginx.
|
18
18
|
|
19
19
|
* `worker_processes` should be *at* *least* the number of CPU cores on
|
20
20
|
a dedicated server (unless you do not have enough memory).
|
@@ -29,7 +29,7 @@ See Pitchfork::Configurator for details on the config file format.
|
|
29
29
|
|
30
30
|
* Bigger is better. The more `worker_processes` you run, the more you'll
|
31
31
|
benefit from Copy-on-Write. If your application use 1GiB of memory after boot,
|
32
|
-
running `10` worker
|
32
|
+
running `10` worker processes, the relative memory usage per worker will only be
|
33
33
|
`~100MiB`, whereas if you only run `5` worker processes, there relative usage will be
|
34
34
|
`~200MiB`.
|
35
35
|
So if you can chose your hardware, it's preferable to use a smaller number
|
data/examples/nginx.conf
CHANGED
@@ -71,7 +71,7 @@ http {
|
|
71
71
|
# this can be any application server, not just unicorn
|
72
72
|
upstream app_server {
|
73
73
|
# fail_timeout=0 means we always retry an upstream even if it failed
|
74
|
-
# to return a good HTTP response (in case the unicorn
|
74
|
+
# to return a good HTTP response (in case the unicorn monitor nukes a
|
75
75
|
# single worker for timing out).
|
76
76
|
|
77
77
|
# for UNIX domain socket setups:
|
data/examples/pitchfork.conf.rb
CHANGED
@@ -26,7 +26,7 @@ run_once = true
|
|
26
26
|
|
27
27
|
after_mold_fork do |server, mold|
|
28
28
|
# Occasionally, it may be necessary to run non-idempotent code in the
|
29
|
-
#
|
29
|
+
# monitor before forking. Keep in mind the above disconnect! example
|
30
30
|
# is idempotent and does not need a guard.
|
31
31
|
if run_once
|
32
32
|
# do_something_once_here ...
|
data/ext/pitchfork_http/c_util.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Generic C functions and macros go here, there are no dependencies
|
3
|
-
* on
|
3
|
+
* on Pitchfork internal structures or the Ruby C API in here.
|
4
4
|
*/
|
5
5
|
|
6
6
|
#ifndef UH_util_h
|
@@ -60,7 +60,7 @@ static int hexchar2int(int xdigit)
|
|
60
60
|
if (xdigit >= 'a' && xdigit <= 'f')
|
61
61
|
return xdigit - 'a' + 10;
|
62
62
|
|
63
|
-
/* Ragel already does runtime range checking for us in
|
63
|
+
/* Ragel already does runtime range checking for us in Pitchfork: */
|
64
64
|
assert(xdigit >= '0' && xdigit <= '9' && "invalid digit character");
|
65
65
|
|
66
66
|
return xdigit - '0';
|
@@ -1,11 +1,11 @@
|
|
1
1
|
/*
|
2
|
-
* This is only intended for use inside a
|
2
|
+
* This is only intended for use inside a pitchfork worker, nowhere else.
|
3
3
|
* EPOLLEXCLUSIVE somewhat mitigates the thundering herd problem for
|
4
4
|
* mostly idle processes since we can't use blocking accept4.
|
5
5
|
* This is NOT intended for use with multi-threaded servers, nor
|
6
6
|
* single-threaded multi-client ("C10K") servers or anything advanced
|
7
7
|
* like that. This use of epoll is only appropriate for a primitive,
|
8
|
-
* single-client, single-threaded servers like
|
8
|
+
* single-client, single-threaded servers like pitchfork that need to
|
9
9
|
* support SIGKILL timeouts and parent death detection.
|
10
10
|
*/
|
11
11
|
#if defined(HAVE_EPOLL_CREATE1)
|
data/lib/pitchfork/children.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Pitchfork
|
5
|
-
# This class keep tracks of the state of all the
|
5
|
+
# This class keep tracks of the state of all the monitor children.
|
6
6
|
class Children
|
7
7
|
attr_reader :mold, :service
|
8
8
|
attr_accessor :last_generation
|