raptor 0.14.0 → 0.15.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/CHANGELOG.md +5 -0
- data/README.md +29 -29
- data/lib/rackup/handler/raptor.rb +3 -3
- data/lib/raptor/cli.rb +2 -2
- data/lib/raptor/server.rb +10 -4
- data/lib/raptor/version.rb +1 -1
- data/sig/generated/raptor/server.rbs +15 -13
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 064ae83daf94da7f8f08e7e8ec641da9d340980d7b79b74f5135a0cb6bbba420
|
|
4
|
+
data.tar.gz: a672546792de83d7567980cd37eb10d123a528b20c741ea03c9edd599e59dd92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 558d707115b817ab6312c0c2b9ea118953b30a642d7d2b6fc7dffd8544fc3cf85b5add06eb97f4db837568cb67fca32f833a729adc89c9d62af2b2194243125f
|
|
7
|
+
data.tar.gz: a6a82af2ad505fd6c452f957b126c58522848163e80df0b6b856054c345837f4c46ce458370670c1a62f33255cfcd24c21df77bb0e556cd4c6f6d53485b95bfb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.15.0] - 2026-08-16
|
|
4
|
+
|
|
5
|
+
- Yield between accepts when the thread pool queue exceeds the pool size
|
|
6
|
+
- Default the worker count to the cgroup-aware available processor count
|
|
7
|
+
|
|
3
8
|
## [0.14.0] - 2026-08-09
|
|
4
9
|
|
|
5
10
|
- Cap eager HTTP/2 frame consumption at thread pool saturation
|
data/README.md
CHANGED
|
@@ -36,23 +36,23 @@ run proc { |_env| [200, { "content-type" => "text/plain" }, ["Hello, World!"]] }
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
> bundle exec raptor -w 4 -t 3 hello_world.ru
|
|
39
|
-
[Raptor
|
|
40
|
-
[Raptor
|
|
41
|
-
[Raptor
|
|
42
|
-
[Raptor
|
|
43
|
-
[Raptor
|
|
44
|
-
[Raptor
|
|
45
|
-
[Raptor
|
|
46
|
-
[Raptor
|
|
47
|
-
[Raptor
|
|
48
|
-
[Raptor
|
|
49
|
-
[Raptor
|
|
50
|
-
[Raptor
|
|
51
|
-
[Raptor
|
|
52
|
-
[Raptor
|
|
53
|
-
[Raptor
|
|
54
|
-
[Raptor
|
|
55
|
-
[Raptor
|
|
39
|
+
[Raptor 33061|Main|Main] Cluster initializing:
|
|
40
|
+
[Raptor 33061|Main|Main] ├─ Version: 0.15.0
|
|
41
|
+
[Raptor 33061|Main|Main] ├─ Ruby Version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
42
|
+
[Raptor 33061|Main|Main] ├─ Environment: development
|
|
43
|
+
[Raptor 33061|Main|Main] ├─ Master PID: 33061
|
|
44
|
+
[Raptor 33061|Main|Main] │ └─ 4 worker processes
|
|
45
|
+
[Raptor 33061|Main|Main] │ ├─ 1 server thread
|
|
46
|
+
[Raptor 33061|Main|Main] │ ├─ 1 reactor thread
|
|
47
|
+
[Raptor 33061|Main|Main] │ ├─ 1 pipeline ractor
|
|
48
|
+
[Raptor 33061|Main|Main] │ ├─ 1 pipeline collector thread
|
|
49
|
+
[Raptor 33061|Main|Main] │ ├─ 3 worker threads
|
|
50
|
+
[Raptor 33061|Main|Main] │ └─ 1 stats thread
|
|
51
|
+
[Raptor 33061|Main|Main] └─ Listening on 0.0.0.0:9292
|
|
52
|
+
[Raptor 33064|Main|Main] Worker 0 booted
|
|
53
|
+
[Raptor 33065|Main|Main] Worker 1 booted
|
|
54
|
+
[Raptor 33066|Main|Main] Worker 2 booted
|
|
55
|
+
[Raptor 33067|Main|Main] Worker 3 booted
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
```
|
|
@@ -193,7 +193,7 @@ Worker 1 (phase 0): pid=91351, requests=1199, busy=1/3, backlog=0, booted, last_
|
|
|
193
193
|
|
|
194
194
|
## (Micro) Benchmarks
|
|
195
195
|
|
|
196
|
-
Raptor 0.
|
|
196
|
+
Raptor 0.15.0 vs Puma 8.0.2 vs PumaPlus 0.1.0 vs Falcon 0.57.0 across two workload profiles. **IO-bound** is a GET
|
|
197
197
|
endpoint that interleaves 5-10 short sleeps (total 2.5-15ms) with small CPU work, simulating a read path that makes
|
|
198
198
|
several DB or cache calls. **CPU-bound** is a POST endpoint that accepts a small JSON body, interleaves 3-5 chunks of
|
|
199
199
|
JSON item building (total 450-1500 items) with sub-100µs sleeps, and returns the built array, simulating a write path
|
|
@@ -202,20 +202,20 @@ that does most of its work in Ruby with a few near-zero-cost cache hits.
|
|
|
202
202
|
Each cell reports the median throughput and median p95 latency independently across 5 runs, so the two numbers in a row
|
|
203
203
|
may come from different runs. Every run starts a fresh server process so the samples are independent of each other;
|
|
204
204
|
state accumulated in a previous run cannot bias the next. Across the whole table, the widest spread
|
|
205
|
-
((max - min) / 2 / median) between runs of a single cell was ±
|
|
205
|
+
((max - min) / 2 / median) between runs of a single cell was ±29.5% for throughput and ±42.2% for p95.
|
|
206
206
|
|
|
207
|
-
| Protocol | Workload | Raptor req/s | Raptor p95 | Puma req/s | Puma p95 | vs Puma req/s | vs Puma p95
|
|
208
|
-
| --------------------- | -------- | ------------ | ---------- | ----------- | --------- | ------------- |
|
|
209
|
-
| HTTP/1.1 | IO |
|
|
210
|
-
| HTTP/1.1 | CPU |
|
|
211
|
-
| HTTP/1.1 (keep-alive) | IO |
|
|
212
|
-
| HTTP/1.1 (keep-alive) | CPU |
|
|
213
|
-
| HTTP/2 | IO | 0.
|
|
214
|
-
| HTTP/2 | CPU |
|
|
207
|
+
| Protocol | Workload | Raptor req/s | Raptor p95 | Puma req/s | Puma p95 | vs Puma req/s | vs Puma p95 | PumaPlus req/s | PumaPlus p95 | vs PumaPlus req/s | vs PumaPlus p95 | Falcon req/s | Falcon p95 | vs Falcon req/s | vs Falcon p95 |
|
|
208
|
+
| --------------------- | -------- | ------------ | ---------- | ----------- | --------- | ------------- | ------------ | -------------- | ------------ | ----------------- | --------------- | ------------ | ---------- | --------------- | ------------- |
|
|
209
|
+
| HTTP/1.1 | IO | 3.28k req/s | 59.90 ms | 1.44k req/s | 132.20 ms | 127.7% higher | 54.7% lower | 1.55k req/s | 91.30 ms | 111.3% higher | 34.4% lower | 12.50k req/s | 13.80 ms | 73.7% lower | 334.1% higher |
|
|
210
|
+
| HTTP/1.1 | CPU | 8.49k req/s | 32.40 ms | 9.08k req/s | 19.40 ms | 6.5% lower | 67.0% higher | 8.79k req/s | 17.40 ms | 3.4% lower | 86.2% higher | 6.89k req/s | 25.50 ms | 23.2% higher | 27.1% higher |
|
|
211
|
+
| HTTP/1.1 (keep-alive) | IO | 2.08k req/s | 54.60 ms | 1.40k req/s | 112.80 ms | 48.0% higher | 51.6% lower | 1.53k req/s | 91.10 ms | 35.8% higher | 40.1% lower | 6.17k req/s | 28.70 ms | 66.3% lower | 90.2% higher |
|
|
212
|
+
| HTTP/1.1 (keep-alive) | CPU | 9.04k req/s | 17.40 ms | 8.92k req/s | 21.30 ms | 1.3% higher | 18.3% lower | 9.04k req/s | 17.00 ms | 0.1% higher | 2.4% higher | 7.32k req/s | 29.90 ms | 23.5% higher | 41.8% lower |
|
|
213
|
+
| HTTP/2 | IO | 0.97k req/s | 201.32 ms | N/A | N/A | - | - | 1.49k req/s | 92.51 ms | 35.0% lower | 117.6% higher | 6.61k req/s | 27.95 ms | 85.4% lower | 620.4% higher |
|
|
214
|
+
| HTTP/2 | CPU | 5.42k req/s | 35.22 ms | N/A | N/A | - | - | 8.61k req/s | 18.18 ms | 37.0% lower | 93.8% higher | 7.32k req/s | 29.95 ms | 25.9% lower | 17.6% higher |
|
|
215
215
|
|
|
216
216
|
> ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [aarch64-linux]
|
|
217
|
-
>
|
|
218
|
-
>
|
|
217
|
+
> 10 worker processes; Raptor, Puma, and PumaPlus run 3 threads per worker, Falcon runs unbounded fibers per worker;
|
|
218
|
+
> 120 concurrent HTTP/1.1 client connections; 40 concurrent HTTP/2 client connections × 3 streams each
|
|
219
219
|
|
|
220
220
|
See [bin/benchmark](bin/benchmark) for more details.
|
|
221
221
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# rbs_inline: enabled
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
4
|
+
require "concurrent/utility/processor_counter"
|
|
5
5
|
|
|
6
6
|
module Rackup
|
|
7
7
|
module Handler
|
|
@@ -42,7 +42,7 @@ module Rackup
|
|
|
42
42
|
{
|
|
43
43
|
"Host=HOST" => "Hostname to listen on (default: #{DEFAULT_OPTIONS[:Host]})",
|
|
44
44
|
"Port=PORT" => "Port to listen on (default: #{DEFAULT_OPTIONS[:Port]})",
|
|
45
|
-
"Workers=NUM" => "Number of worker processes (default:
|
|
45
|
+
"Workers=NUM" => "Number of worker processes (default: available processor count)",
|
|
46
46
|
"Ractors=NUM" => "Number of pipeline ractors per worker (default: 1)",
|
|
47
47
|
"Threads=NUM" => "Number of threads per worker (default: 3)",
|
|
48
48
|
"Config=PATH" => "Load additional configuration from PATH"
|
|
@@ -80,7 +80,7 @@ module Rackup
|
|
|
80
80
|
end,
|
|
81
81
|
socket_backlog: (config[:socket_backlog] || cli_defaults[:socket_backlog]).to_i,
|
|
82
82
|
drain_accept_queue: config.key?(:drain_accept_queue) ? config[:drain_accept_queue] : cli_defaults[:drain_accept_queue],
|
|
83
|
-
workers: (options[:Workers] || config[:workers] ||
|
|
83
|
+
workers: (options[:Workers] || config[:workers] || Concurrent.available_processor_count).to_i,
|
|
84
84
|
ractors: (options[:Ractors] || config[:ractors] || cli_defaults[:ractors]).to_i,
|
|
85
85
|
threads: (options[:Threads] || config[:threads] || cli_defaults[:threads]).to_i,
|
|
86
86
|
app: app
|
data/lib/raptor/cli.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# rbs_inline: enabled
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
4
|
+
require "concurrent/utility/processor_counter"
|
|
5
5
|
require "json"
|
|
6
6
|
require "optparse"
|
|
7
7
|
|
|
@@ -24,7 +24,7 @@ module Raptor
|
|
|
24
24
|
# cli.run
|
|
25
25
|
#
|
|
26
26
|
class CLI
|
|
27
|
-
DEFAULT_WORKER_COUNT =
|
|
27
|
+
DEFAULT_WORKER_COUNT = Integer(Concurrent.available_processor_count)
|
|
28
28
|
|
|
29
29
|
NESTED_OPTION_KEYS = [:connection, :http1, :http2].freeze
|
|
30
30
|
|
data/lib/raptor/server.rb
CHANGED
|
@@ -9,9 +9,9 @@ require_relative "reuseport_bpf"
|
|
|
9
9
|
|
|
10
10
|
module Raptor
|
|
11
11
|
# Accepts client connections on TCP, Unix, and SSL listeners and
|
|
12
|
-
# dispatches them into the request pipeline.
|
|
13
|
-
# when the
|
|
14
|
-
#
|
|
12
|
+
# dispatches them into the request pipeline. Yields between accepts
|
|
13
|
+
# when the thread pool queue exceeds the pool size so overloaded
|
|
14
|
+
# workers stay responsive to in-flight requests.
|
|
15
15
|
#
|
|
16
16
|
class Server
|
|
17
17
|
HTTP_SCHEME = "http"
|
|
@@ -22,6 +22,7 @@ module Raptor
|
|
|
22
22
|
DEFAULT_REMOTE_ADDR = "127.0.0.1"
|
|
23
23
|
DEFAULT_SERVER_NAME = "localhost"
|
|
24
24
|
|
|
25
|
+
BACKPRESSURE_THRESHOLD_MULTIPLIER = 1.2
|
|
25
26
|
MIN_BACKPRESSURE_THRESHOLD = 8
|
|
26
27
|
|
|
27
28
|
# @rbs @binder: Binder
|
|
@@ -73,7 +74,7 @@ module Raptor
|
|
|
73
74
|
Thread.new do
|
|
74
75
|
Thread.current.name = "Server"
|
|
75
76
|
|
|
76
|
-
backpressure_threshold = [(@thread_pool.size *
|
|
77
|
+
backpressure_threshold = [(@thread_pool.size * BACKPRESSURE_THRESHOLD_MULTIPLIER).ceil, MIN_BACKPRESSURE_THRESHOLD].max
|
|
77
78
|
|
|
78
79
|
while @running.true?
|
|
79
80
|
begin
|
|
@@ -85,6 +86,11 @@ module Raptor
|
|
|
85
86
|
next unless ready_servers
|
|
86
87
|
next if @reactor.backlog >= backpressure_threshold
|
|
87
88
|
|
|
89
|
+
if @thread_pool.queue_size > @thread_pool.size
|
|
90
|
+
Thread.pass
|
|
91
|
+
next
|
|
92
|
+
end
|
|
93
|
+
|
|
88
94
|
ready_servers.each { |listener| accept_connection(listener) }
|
|
89
95
|
end
|
|
90
96
|
end
|
data/lib/raptor/version.rb
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Raptor
|
|
4
4
|
# Accepts client connections on TCP, Unix, and SSL listeners and
|
|
5
|
-
# dispatches them into the request pipeline.
|
|
6
|
-
# when the
|
|
7
|
-
#
|
|
5
|
+
# dispatches them into the request pipeline. Yields between accepts
|
|
6
|
+
# when the thread pool queue exceeds the pool size so overloaded
|
|
7
|
+
# workers stay responsive to in-flight requests.
|
|
8
8
|
class Server
|
|
9
9
|
HTTP_SCHEME: ::String
|
|
10
10
|
|
|
@@ -16,27 +16,29 @@ module Raptor
|
|
|
16
16
|
|
|
17
17
|
DEFAULT_SERVER_NAME: ::String
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
BACKPRESSURE_THRESHOLD_MULTIPLIER: ::Float
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
MIN_BACKPRESSURE_THRESHOLD: ::Integer
|
|
22
22
|
|
|
23
|
-
@
|
|
23
|
+
@binder: Binder
|
|
24
24
|
|
|
25
|
-
@
|
|
25
|
+
@listeners: Array[TCPServer | UNIXServer | Binder::SslListener]
|
|
26
26
|
|
|
27
|
-
@
|
|
27
|
+
@reactor: Reactor
|
|
28
28
|
|
|
29
|
-
@
|
|
29
|
+
@thread_pool: AtomicThreadPool
|
|
30
30
|
|
|
31
31
|
@http1: Http1
|
|
32
32
|
|
|
33
|
-
@
|
|
33
|
+
@http2: Http2
|
|
34
34
|
|
|
35
|
-
@
|
|
35
|
+
@first_data_timeout: Integer
|
|
36
36
|
|
|
37
|
-
@
|
|
37
|
+
@drain_accept_queue: bool
|
|
38
38
|
|
|
39
|
-
@
|
|
39
|
+
@bpf_active: bool
|
|
40
|
+
|
|
41
|
+
@running: AtomicBoolean
|
|
40
42
|
|
|
41
43
|
# Creates a new Server instance.
|
|
42
44
|
#
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raptor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -51,6 +51,20 @@ dependencies:
|
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: concurrent-ruby
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
54
68
|
- !ruby/object:Gem::Dependency
|
|
55
69
|
name: ractor-pool
|
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|