pitchfork 0.14.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +16 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +3 -0
- data/docs/CONFIGURATION.md +32 -0
- data/docs/FORK_SAFETY.md +2 -1
- data/ext/pitchfork_http/common_field_optimization.h +8 -5
- data/ext/pitchfork_http/extconf.rb +3 -0
- data/ext/pitchfork_http/pitchfork_http.c +292 -468
- data/ext/pitchfork_http/pitchfork_http.rl +32 -24
- data/lib/pitchfork/chunked.rb +6 -3
- data/lib/pitchfork/configurator.rb +1 -1
- data/lib/pitchfork/http_parser.rb +0 -1
- data/lib/pitchfork/http_response.rb +3 -1
- data/lib/pitchfork/http_server.rb +48 -24
- data/lib/pitchfork/listeners.rb +65 -0
- data/lib/pitchfork/socket_helper.rb +12 -2
- data/lib/pitchfork/version.rb +1 -1
- data/lib/pitchfork/worker.rb +0 -5
- data/pitchfork.gemspec +2 -1
- metadata +18 -4
- data/Gemfile.lock +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96240978a658c76297ea22353c5851d80bee9f033a74420b025d9941e32476be
|
4
|
+
data.tar.gz: fb90757e6e6a86e31e43bfed1589ed8ecf95c5f3d6f7cbe9802e10f588dd68b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcfffa4d9e8cb3e92c3dbd89d5a3c32577e5170a039d0e3fd71d5b57b408c6d2cadaf2bb42009cc14714de75b60c42fe3e0273d01bf8f9d49777e09f4d137e2a
|
7
|
+
data.tar.gz: d663cbd0e73221ab8dff5dafb2696293cb2552d2026ae6faa0a4c4d28c61ae672d6745c1de5b52baaa5062c4d08ed2d0945ac0986e05cc20e62f713bb8fda84a
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,7 +4,7 @@ on: [push, pull_request]
|
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
ruby:
|
7
|
-
name: Ruby ${{ matrix.ruby }} ${{ matrix.rubyopt }}
|
7
|
+
name: Ruby ${{ matrix.ruby }} / Rack ${{ matrix.rack }} ${{ matrix.rubyopt }}
|
8
8
|
timeout-minutes: 15
|
9
9
|
strategy:
|
10
10
|
fail-fast: false
|
@@ -12,15 +12,24 @@ jobs:
|
|
12
12
|
os: ["ubuntu-latest"]
|
13
13
|
ruby: ["ruby-head", "3.3", "3.2", "3.1", "3.0", "2.7", "2.6"]
|
14
14
|
rubyopt: [""]
|
15
|
+
rack: ["~> 3.1"]
|
15
16
|
include:
|
16
17
|
- ruby: "3.3"
|
17
18
|
rubyopt: "--enable-frozen-string-literal"
|
19
|
+
rack: "~> 3.1"
|
20
|
+
- ruby: "3.3"
|
21
|
+
rack: "~> 3.0.0"
|
22
|
+
- ruby: "3.3"
|
23
|
+
rack: "~> 2.0"
|
24
|
+
env:
|
25
|
+
RACK_VERSION: "${{ matrix.rack }}"
|
26
|
+
RUBYOPT: "${{ matrix.rubyopt }}"
|
18
27
|
runs-on: ubuntu-latest
|
19
28
|
steps:
|
20
29
|
- name: Check out code
|
21
30
|
uses: actions/checkout@v4
|
22
31
|
|
23
|
-
- name: Set up Ruby
|
32
|
+
- name: Set up Ruby ${{ matrix.ruby }}
|
24
33
|
uses: ruby/setup-ruby@v1
|
25
34
|
with:
|
26
35
|
ruby-version: ${{ matrix.ruby }}
|
@@ -29,5 +38,8 @@ jobs:
|
|
29
38
|
- name: Install packages
|
30
39
|
run: sudo apt-get install -y ragel socat netcat
|
31
40
|
|
32
|
-
- name: Tests ${{ matrix.rubyopt }}
|
33
|
-
run:
|
41
|
+
- name: Tests Rack ${{ matrix.rack }} ${{ matrix.rubyopt }}
|
42
|
+
run: bundle exec rake
|
43
|
+
|
44
|
+
- name: Ensure ragel output is up-to-date
|
45
|
+
run: git diff --exit-code
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 0.16.0
|
4
|
+
|
5
|
+
- Use `exit!` for exiting the middle process when forking a new worker or mold.
|
6
|
+
This skips `at_exit` and finalizer hooks, which shouldn't be needed.
|
7
|
+
|
8
|
+
# 0.15.0
|
9
|
+
|
10
|
+
- Encode pure ASCII strings in Rack env as UTF-8, as allowed by the rack spec.
|
11
|
+
Other strings remain as ASCII-8BIT aka BINARY as required by the rack spec.
|
12
|
+
- Fix compatibility with Rack 3.1.
|
13
|
+
- Fix `rack.hijack` support.
|
14
|
+
- Support Rack 3 streaming bodies.
|
15
|
+
- Implement listen queues for fairer load balancing (optional).
|
16
|
+
- Assume C99 compatible compiler.
|
17
|
+
- Declare dependency on `logger` for Ruby 3.5 compatibility.
|
18
|
+
|
3
19
|
# 0.14.0
|
4
20
|
|
5
21
|
- Remove the dependency on `raindrops`.
|
data/Gemfile
CHANGED
data/docs/CONFIGURATION.md
CHANGED
@@ -60,6 +60,10 @@ The following options may be specified (but are generally not needed):
|
|
60
60
|
|
61
61
|
Default: `1024`
|
62
62
|
|
63
|
+
Note: if the `queue` option is used, each queue gets an equal share of the
|
64
|
+
total `backlog`. e.g. `backlog: 1028, queues: 8` create `8` sockets with a
|
65
|
+
backlog of `128`.
|
66
|
+
|
63
67
|
Note: with the Linux kernel, the net.core.somaxconn sysctl defaults
|
64
68
|
to 128, capping this value to 128. Raising the sysctl allows a
|
65
69
|
larger backlog (which may not be desirable with multiple,
|
@@ -136,6 +140,34 @@ The following options may be specified (but are generally not needed):
|
|
136
140
|
|
137
141
|
Default: `false` (unset)
|
138
142
|
|
143
|
+
- `queues: Integer`
|
144
|
+
|
145
|
+
Create multiple server sockets (using `reuseport`) and split them
|
146
|
+
between workers to ensure fairer load balancing.
|
147
|
+
|
148
|
+
Linux's `epoll+accept` queue is fundamentally LIFO (see a good writeup at
|
149
|
+
https://blog.cloudflare.com/the-sad-state-of-linux-socket-balancing/).
|
150
|
+
|
151
|
+
Because of this, the workers with the lowest PID will accept
|
152
|
+
disproportionally more requests than workers with higher PID.
|
153
|
+
It generally isn't a problem, especially when reforking is enabled, but for
|
154
|
+
applications that are routinely over provisioned, it may be desirable to
|
155
|
+
ensure all workers at least get some incoming requests so the can warm up.
|
156
|
+
|
157
|
+
Creating more than one queue allow to restrict which worker can process
|
158
|
+
a given incomming request, hence making the load balancing fairer.
|
159
|
+
|
160
|
+
However it is to be used with care, because if the queueing is made too
|
161
|
+
granular, this may cause pockets of request queueing.
|
162
|
+
|
163
|
+
Default: `1` (unset)
|
164
|
+
|
165
|
+
- `queues_per_worker: Integer`
|
166
|
+
|
167
|
+
Controls how many queues each worker is assigned.
|
168
|
+
|
169
|
+
Default: `queues - 1`.
|
170
|
+
|
139
171
|
- `umask: mode`
|
140
172
|
|
141
173
|
Sets the file mode creation mask for UNIX sockets.
|
data/docs/FORK_SAFETY.md
CHANGED
@@ -83,7 +83,8 @@ impact of discovering such bug.
|
|
83
83
|
- The `grpc` isn't fork safe by default, but starting from version `1.57.0`, it does provide an experimental
|
84
84
|
fork safe option that requires setting an environment variable before loading the library, and calling
|
85
85
|
`GRPC.prefork`, `GRPC.postfork_parent` and `GRPC.postfork_child` around fork calls.
|
86
|
-
(https://github.com/grpc/grpc/pull/33430)
|
86
|
+
(https://github.com/grpc/grpc/pull/33430).
|
87
|
+
You can also use the [`grpc_fork_safety`](https://github.com/Shopify/grpc_fork_safety) gem to make it easier.
|
87
88
|
|
88
89
|
- The `ruby-vips` gem binds the `libvips` image processing library that isn't fork safe.
|
89
90
|
(https://github.com/libvips/libvips/discussions/3577)
|
@@ -61,19 +61,20 @@ static struct common_field common_http_fields[] = {
|
|
61
61
|
#define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
|
62
62
|
static ID id_uminus;
|
63
63
|
|
64
|
+
/* This helper is used to create rack env keys, they should be UTF-8 */
|
64
65
|
#ifdef HAVE_RB_ENC_INTERNED_STR
|
65
66
|
static VALUE str_new_dd_freeze(const char *ptr, long len)
|
66
67
|
{
|
67
68
|
if (RB_ENC_INTERNED_STR_NULL_CHECK && len == 0) {
|
68
|
-
return rb_enc_interned_str("", len,
|
69
|
+
return rb_enc_interned_str("", len, rb_utf8_encoding());
|
69
70
|
} else {
|
70
|
-
return rb_enc_interned_str(ptr, len,
|
71
|
+
return rb_enc_interned_str(ptr, len, rb_utf8_encoding());
|
71
72
|
}
|
72
73
|
}
|
73
74
|
#else
|
74
75
|
static VALUE str_new_dd_freeze(const char *ptr, long len)
|
75
76
|
{
|
76
|
-
VALUE str =
|
77
|
+
VALUE str = rb_utf8_str_new(ptr, len);
|
77
78
|
return rb_funcall(str, id_uminus, 0);
|
78
79
|
}
|
79
80
|
#endif
|
@@ -119,12 +120,14 @@ static VALUE find_common_field(const char *field, size_t flen)
|
|
119
120
|
*/
|
120
121
|
static VALUE uncommon_field(const char *field, size_t flen)
|
121
122
|
{
|
122
|
-
VALUE f =
|
123
|
+
VALUE f = rb_utf8_str_new(NULL, HTTP_PREFIX_LEN + flen);
|
123
124
|
memcpy(RSTRING_PTR(f), HTTP_PREFIX, HTTP_PREFIX_LEN);
|
124
125
|
memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
|
125
126
|
assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0' &&
|
126
127
|
"string didn't end with \\0"); /* paranoia */
|
127
|
-
|
128
|
+
// We freeze the value because it will be used as a hash key,
|
129
|
+
// so if we don't Hash#[]= will dup it.
|
130
|
+
return rb_str_freeze(f);
|
128
131
|
}
|
129
132
|
|
130
133
|
#endif /* common_field_optimization_h */
|
@@ -3,9 +3,12 @@
|
|
3
3
|
require 'mkmf'
|
4
4
|
|
5
5
|
append_cflags("-fvisibility=hidden")
|
6
|
+
append_cflags("-std=c99")
|
7
|
+
|
6
8
|
have_const("PR_SET_CHILD_SUBREAPER", "sys/prctl.h")
|
7
9
|
have_func("rb_enc_interned_str", "ruby.h") # Ruby 3.0+
|
8
10
|
have_func("rb_io_descriptor", "ruby.h") # Ruby 3.1+
|
11
|
+
have_func("rb_hash_new_capa", "ruby.h") # Ruby 3.2+
|
9
12
|
have_func("getpagesize", "unistd.h")
|
10
13
|
|
11
14
|
if RUBY_VERSION.start_with?('3.0.')
|