pitchfork 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +14 -7
- data/docs/CONFIGURATION.md +13 -0
- data/docs/WHY_MIGRATE.md +93 -0
- data/lib/pitchfork/configurator.rb +5 -0
- data/lib/pitchfork/http_server.rb +5 -1
- data/lib/pitchfork/info.rb +25 -4
- data/lib/pitchfork/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb4e22969b9f2c38717f0cfa7a3c966995814156a17589bc06bdc609b7ad6e32
|
4
|
+
data.tar.gz: dbf7833c26ef94962abbd71d66c63e40dd0f7f405ee82951723ad3b4cbfa864f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f0c029a01bc999d90421fe0ed77f76c6f1e56a9f3ec8eaa4ab6722f40eb0ee7f9aa0f004044e4c97e93a593cdba0d7a6bab01ef6b075440c76012f05e5cccd4
|
7
|
+
data.tar.gz: 4ae4d319ffd2acbf99ad29156622510c951ca095c20074f8415376d6e217be1b959e68e3245590cce62de66f3f8af8f0aae469fec842865dd4dcfe1b060e3db9
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,13 +9,6 @@ advantage of features in Unix/Unix-like kernels. Slow clients should
|
|
9
9
|
only be served by placing a reverse proxy capable of fully buffering
|
10
10
|
both the request and response in between `pitchfork` and slow clients.
|
11
11
|
|
12
|
-
## Disclaimer
|
13
|
-
|
14
|
-
Until this notice is removed from the README, `pitchfork` should be
|
15
|
-
considered experimental. As such it is not encouraged to run it in
|
16
|
-
production just yet unless you feel capable of debugging yourself
|
17
|
-
any issue that may arise.
|
18
|
-
|
19
12
|
## Features
|
20
13
|
|
21
14
|
* Designed for Rack, Linux, fast clients, and ease-of-debugging. We
|
@@ -40,9 +33,23 @@ any issue that may arise.
|
|
40
33
|
or ports yourself. `pitchfork` can spawn and manage any number of
|
41
34
|
worker processes you choose to scale to your backend.
|
42
35
|
|
36
|
+
* Adaptative timeout: request timeout can be extended dynamically on a
|
37
|
+
per request basis, which allows to keep a strict overall timeout for
|
38
|
+
most endpoints, but allow a few endpoints to take longer.
|
39
|
+
|
43
40
|
* Load balancing is done entirely by the operating system kernel.
|
44
41
|
Requests never pile up behind a busy worker process.
|
45
42
|
|
43
|
+
## When to Use
|
44
|
+
|
45
|
+
Pitchfork isn't inherently better than other Ruby application servers, it mostly
|
46
|
+
focus on different tradeoffs.
|
47
|
+
|
48
|
+
If you are fine with your current server, it's best to stick with it.
|
49
|
+
|
50
|
+
If there is a problem you are trying to solve, please read the
|
51
|
+
[migration guide](docs/WHY_MIGRATE.md) first.
|
52
|
+
|
46
53
|
## Requirements
|
47
54
|
|
48
55
|
Ruby(MRI) Version 2.5 and above.
|
data/docs/CONFIGURATION.md
CHANGED
@@ -238,6 +238,19 @@ exit or be SIGKILL-ed due to timeouts.
|
|
238
238
|
See https://nginx.org/en/docs/http/ngx_http_upstream_module.html
|
239
239
|
for more details on nginx upstream configuration.
|
240
240
|
|
241
|
+
### `spawn_timeout`
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
timeout 5
|
245
|
+
```
|
246
|
+
|
247
|
+
Sets the timeout for a newly spawned worker to be ready after being spawned.
|
248
|
+
|
249
|
+
This timeout is a safeguard against various low-level fork safety bugs that could cause
|
250
|
+
a process to dead-lock.
|
251
|
+
|
252
|
+
The default of `10` seconds is quite generous and likely doesn't need to be adjusted.
|
253
|
+
|
241
254
|
### `logger`
|
242
255
|
|
243
256
|
```ruby
|
data/docs/WHY_MIGRATE.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Why migrate to Pitchfork?
|
2
|
+
|
3
|
+
First and foremost, if you don't have any specific problem with your current server, then don't.
|
4
|
+
|
5
|
+
Pitchfork isn't a silver bullet, it's a very opinionated software that focus on very specific tradeoffs,
|
6
|
+
that are different from other servers.
|
7
|
+
|
8
|
+
## Coming from Unicorn
|
9
|
+
|
10
|
+
### Why Migrate?
|
11
|
+
|
12
|
+
#### Adaptative timeout
|
13
|
+
|
14
|
+
Pitchfork allows to extend the request timeout on a per request basis,
|
15
|
+
this can be helpful when trying to reduce the global request timeout
|
16
|
+
to a saner value. You can enforce a stricter value, and extend it
|
17
|
+
in the minority of offending endpoints.
|
18
|
+
|
19
|
+
#### Memory Usage - Reforking
|
20
|
+
|
21
|
+
If you are unsatisfied with Unicorn memory usage, but threaded Puma isn't an option
|
22
|
+
for you, then Pitchfork may be an option if you are able to enable reforking.
|
23
|
+
|
24
|
+
However be warned that making an application fork safe can be non-trivial,
|
25
|
+
and mistakes can lead to critical bugs.
|
26
|
+
|
27
|
+
#### Rack 3
|
28
|
+
|
29
|
+
As of Unicorn `6.1.0`, Rack 3 isn't yet supported by Unicorn.
|
30
|
+
|
31
|
+
Pitchfork is compatible with Rack 3.
|
32
|
+
|
33
|
+
### Why Not Migrate?
|
34
|
+
|
35
|
+
#### Reduced Features
|
36
|
+
|
37
|
+
While Pitchfork started as a fork of Unicorn, many features such as daemonization,
|
38
|
+
pid file management, hot reload have been stripped.
|
39
|
+
|
40
|
+
Pitchfork only kept features that makes sense in a containerized world.
|
41
|
+
|
42
|
+
## Coming from Puma
|
43
|
+
|
44
|
+
Generally speaking, compared to (threaded) Puma, Pitchfork *may* offer better latency and isolation at the expense of throughput.
|
45
|
+
|
46
|
+
### Why Migrate?
|
47
|
+
|
48
|
+
#### Latency
|
49
|
+
|
50
|
+
If you suspect your application is subject to contention on the GVL or some other in-process shared resources,
|
51
|
+
then Pitchfork may offer improved latency.
|
52
|
+
|
53
|
+
It is however heavily recommended to first confirm this suspicion with profiling
|
54
|
+
tools such as [gvltools](https://github.com/Shopify/gvltools).
|
55
|
+
|
56
|
+
If you application isn't subject to in-process contention, Pitchfork is unlikely to improve latency.
|
57
|
+
|
58
|
+
#### Out of Band Garbage Collection
|
59
|
+
|
60
|
+
Another advantage of only processing a single request per process is that
|
61
|
+
[it allows to periodically trigger garbage collection when the worker isn't processing any request](https://shopify.engineering/adventures-in-garbage-collection).
|
62
|
+
|
63
|
+
This can significantly improve tail latency at the expense of throughput.
|
64
|
+
|
65
|
+
#### Resiliency and Isolation
|
66
|
+
|
67
|
+
Since Pitchfork workers have their own address space and only process one request at a time
|
68
|
+
it makes it much harder for one faulty request to impact another.
|
69
|
+
|
70
|
+
Even if a bug causes Ruby to crash, only the request that triggered the bug will be impacted.
|
71
|
+
|
72
|
+
If a bug causes Ruby to hang, the monitor process will SIGKILL the worker and the capacity will be
|
73
|
+
reclaimed.
|
74
|
+
|
75
|
+
This makes Pitchfork more resilient to some classes of bugs.
|
76
|
+
|
77
|
+
#### Thread Safety
|
78
|
+
|
79
|
+
Pitchfork doesn't require applications to be thread-safe. That is probably the worst reason
|
80
|
+
to migrate though.
|
81
|
+
|
82
|
+
### Why Not Migrate?
|
83
|
+
|
84
|
+
#### Memory Usage
|
85
|
+
|
86
|
+
Without reforking enabled Pitchfork will without a doubt use more memory than threaded Puma.
|
87
|
+
|
88
|
+
With reforking enabled, results will vary based on the application profile and the number of Puma threads,
|
89
|
+
but should be in the same ballpark, sometimes better, but likely worse, this depends on many variables and
|
90
|
+
can't really be predicted.
|
91
|
+
|
92
|
+
However be warned that [making an application fork safe](FORK_SAFETY.md) can be non-trivial,
|
93
|
+
and mistakes can lead to critical bugs.
|
@@ -33,6 +33,7 @@ module Pitchfork
|
|
33
33
|
DEFAULTS = {
|
34
34
|
:soft_timeout => 20,
|
35
35
|
:cleanup_timeout => 2,
|
36
|
+
:spawn_timeout => 10,
|
36
37
|
:timeout => 22,
|
37
38
|
:logger => default_logger,
|
38
39
|
:worker_processes => 1,
|
@@ -174,6 +175,10 @@ module Pitchfork
|
|
174
175
|
set_int(:timeout, soft_timeout + cleanup_timeout, 5)
|
175
176
|
end
|
176
177
|
|
178
|
+
def spawn_timeout(seconds)
|
179
|
+
set_int(:spawn_timeout, seconds, 1)
|
180
|
+
end
|
181
|
+
|
177
182
|
def worker_processes(nr)
|
178
183
|
set_int(:worker_processes, nr, 1)
|
179
184
|
end
|
@@ -74,7 +74,7 @@ module Pitchfork
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# :stopdoc:
|
77
|
-
attr_accessor :app, :timeout, :soft_timeout, :cleanup_timeout, :worker_processes,
|
77
|
+
attr_accessor :app, :timeout, :soft_timeout, :cleanup_timeout, :spawn_timeout, :worker_processes,
|
78
78
|
:after_worker_fork, :after_mold_fork,
|
79
79
|
:listener_opts, :children,
|
80
80
|
:orig_app, :config, :ready_pipe,
|
@@ -556,6 +556,10 @@ module Pitchfork
|
|
556
556
|
def spawn_worker(worker, detach:)
|
557
557
|
logger.info("worker=#{worker.nr} gen=#{worker.generation} spawning...")
|
558
558
|
|
559
|
+
# We set the deadline before spawning the child so that if for some
|
560
|
+
# reason it gets stuck before reaching the worker loop,
|
561
|
+
# the monitor process will kill it.
|
562
|
+
worker.update_deadline(@spawn_timeout)
|
559
563
|
Pitchfork.fork_sibling do
|
560
564
|
worker.pid = Process.pid
|
561
565
|
|
data/lib/pitchfork/info.rb
CHANGED
@@ -6,14 +6,35 @@ module Pitchfork
|
|
6
6
|
module Info
|
7
7
|
@workers_count = 0
|
8
8
|
@fork_safe = true
|
9
|
-
|
9
|
+
|
10
|
+
class WeakSet # :nodoc
|
11
|
+
def initialize
|
12
|
+
@map = ObjectSpace::WeakMap.new
|
13
|
+
end
|
14
|
+
|
15
|
+
if RUBY_VERSION < "2.7"
|
16
|
+
def <<(object)
|
17
|
+
@map[object] = object
|
18
|
+
end
|
19
|
+
else
|
20
|
+
def <<(object)
|
21
|
+
@map[object] = true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
@map.each_key(&block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@kept_ios = WeakSet.new
|
10
31
|
|
11
32
|
class << self
|
12
33
|
attr_accessor :workers_count
|
13
34
|
|
14
35
|
def keep_io(io)
|
15
36
|
raise ArgumentError, "#{io.inspect} doesn't respond to :to_io" unless io.respond_to?(:to_io)
|
16
|
-
@kept_ios
|
37
|
+
@kept_ios << io
|
17
38
|
io
|
18
39
|
end
|
19
40
|
|
@@ -22,9 +43,9 @@ module Pitchfork
|
|
22
43
|
end
|
23
44
|
|
24
45
|
def close_all_ios!
|
25
|
-
ignored_ios = [$stdin, $stdout, $stderr]
|
46
|
+
ignored_ios = [$stdin, $stdout, $stderr, STDIN, STDOUT, STDERR].uniq.compact
|
26
47
|
|
27
|
-
@kept_ios.
|
48
|
+
@kept_ios.each do |io_like|
|
28
49
|
ignored_ios << (io_like.is_a?(IO) ? io_like : io_like.to_io)
|
29
50
|
end
|
30
51
|
|
data/lib/pitchfork/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pitchfork
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: raindrops
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- docs/REFORKING.md
|
73
73
|
- docs/SIGNALS.md
|
74
74
|
- docs/TUNING.md
|
75
|
+
- docs/WHY_MIGRATE.md
|
75
76
|
- examples/constant_caches.ru
|
76
77
|
- examples/echo.ru
|
77
78
|
- examples/hello.ru
|