raptor 0.4.0 → 0.5.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/.mise.toml +2 -0
- data/Brewfile +2 -0
- data/CHANGELOG.md +8 -0
- data/README.md +27 -24
- data/lib/rackup/handler/raptor.rb +18 -20
- data/lib/raptor/cli.rb +26 -10
- data/lib/raptor/cluster.rb +128 -56
- data/lib/raptor/http2.rb +4 -3
- data/lib/raptor/log.rb +55 -0
- data/lib/raptor/reactor.rb +25 -29
- data/lib/raptor/request.rb +10 -16
- data/lib/raptor/server.rb +17 -19
- data/lib/raptor/stats.rb +30 -26
- data/lib/raptor/version.rb +1 -1
- data/sig/generated/raptor/cli.rbs +1 -1
- data/sig/generated/raptor/cluster.rbs +69 -37
- data/sig/generated/raptor/http2.rbs +2 -1
- data/sig/generated/raptor/log.rbs +41 -0
- data/sig/generated/raptor/reactor.rbs +23 -26
- data/sig/generated/raptor/request.rbs +6 -13
- data/sig/generated/raptor/server.rbs +14 -16
- data/sig/generated/raptor/stats.rbs +24 -20
- metadata +5 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Generated from lib/raptor/log.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Shared logging helpers. Every line is prefixed with
|
|
5
|
+
# `[Raptor <pid>|<ractor>|<thread>]` so output is identifiable
|
|
6
|
+
# and traceable to its source in a mixed log stream.
|
|
7
|
+
module Log
|
|
8
|
+
# Writes an informational message to stdout.
|
|
9
|
+
#
|
|
10
|
+
# @param message [String] the message to log
|
|
11
|
+
# @return [void]
|
|
12
|
+
#
|
|
13
|
+
# @rbs (String message) -> void
|
|
14
|
+
def self.info: (String message) -> void
|
|
15
|
+
|
|
16
|
+
# Writes a warning to stderr.
|
|
17
|
+
#
|
|
18
|
+
# @param message [String] the message to log
|
|
19
|
+
# @return [void]
|
|
20
|
+
#
|
|
21
|
+
# @rbs (String message) -> void
|
|
22
|
+
def self.warn: (String message) -> void
|
|
23
|
+
|
|
24
|
+
# Logs a rescued exception to stderr. The full message (class,
|
|
25
|
+
# message, backtrace) is written on subsequent unprefixed lines.
|
|
26
|
+
#
|
|
27
|
+
# @param error [Exception] the rescued exception
|
|
28
|
+
# @return [void]
|
|
29
|
+
#
|
|
30
|
+
# @rbs (Exception error) -> void
|
|
31
|
+
def self.rescued_error: (Exception error) -> void
|
|
32
|
+
|
|
33
|
+
# Builds the log line prefix from the current process, ractor,
|
|
34
|
+
# and thread. Unnamed ractors and threads are reported as `main`.
|
|
35
|
+
#
|
|
36
|
+
# @return [String] the prefix
|
|
37
|
+
#
|
|
38
|
+
# @rbs () -> String
|
|
39
|
+
def self.prefix: () -> String
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -5,12 +5,12 @@ module Raptor
|
|
|
5
5
|
#
|
|
6
6
|
# Reactor uses NIO selectors for efficient I/O multiplexing and implements
|
|
7
7
|
# client timeouts using a red-black tree for O(log n) timeout management.
|
|
8
|
-
# It coordinates between
|
|
9
|
-
# pools for
|
|
10
|
-
#
|
|
8
|
+
# It coordinates between ractor pools for CPU-intensive HTTP parsing and
|
|
9
|
+
# thread pools for blocking operations, and provides backlog metrics that
|
|
10
|
+
# the server uses for backpressure control to prevent overload.
|
|
11
11
|
#
|
|
12
12
|
# @example
|
|
13
|
-
# reactor = Reactor.new(
|
|
13
|
+
# reactor = Reactor.new(ractor_pool, thread_pool, client_options: {
|
|
14
14
|
# first_data_timeout: 30,
|
|
15
15
|
# chunk_data_timeout: 10
|
|
16
16
|
# })
|
|
@@ -19,33 +19,33 @@ module Raptor
|
|
|
19
19
|
# # ... later
|
|
20
20
|
# reactor.shutdown
|
|
21
21
|
class Reactor
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# TimeoutClient extends RedBlackTree::Node to enable efficient timeout
|
|
25
|
-
# management using the tree's ordering properties.
|
|
22
|
+
# A client connection node ordered by absolute expiry time so the
|
|
23
|
+
# soonest-to-expire is always at the tree's minimum.
|
|
26
24
|
class TimeoutClient < RedBlackTree::Node
|
|
27
25
|
# @rbs attr_accessor timeout_at: Float
|
|
28
26
|
attr_accessor timeout_at: untyped
|
|
29
27
|
|
|
30
|
-
#
|
|
28
|
+
# Semantic alias for the inherited `data` slot.
|
|
31
29
|
#
|
|
32
|
-
# @return [Hash] the client connection state
|
|
30
|
+
# @return [Hash] the client connection state
|
|
33
31
|
#
|
|
34
32
|
# @rbs () -> Hash[Symbol, untyped]
|
|
35
33
|
def client_data: () -> Hash[Symbol, untyped]
|
|
36
34
|
|
|
37
|
-
#
|
|
35
|
+
# Returns seconds until expiry, clamped to 0 so an already-expired
|
|
36
|
+
# client doesn't push the next selector wait into the future.
|
|
38
37
|
#
|
|
39
38
|
# @param now [Float] current monotonic timestamp
|
|
40
|
-
# @return [Float]
|
|
39
|
+
# @return [Float] seconds until expiry, never negative
|
|
41
40
|
#
|
|
42
41
|
# @rbs (Float now) -> Float
|
|
43
42
|
def timeout: (Float now) -> Float
|
|
44
43
|
|
|
45
|
-
#
|
|
44
|
+
# Orders nodes by `timeout_at` so the tree minimum is the next
|
|
45
|
+
# client to expire.
|
|
46
46
|
#
|
|
47
47
|
# @param other [TimeoutClient] another timeout client to compare
|
|
48
|
-
# @return [Integer] -1, 0, or 1
|
|
48
|
+
# @return [Integer] -1, 0, or 1
|
|
49
49
|
#
|
|
50
50
|
# @rbs (TimeoutClient other) -> Integer
|
|
51
51
|
def <=>: (TimeoutClient other) -> Integer
|
|
@@ -79,16 +79,16 @@ module Raptor
|
|
|
79
79
|
|
|
80
80
|
# Creates a new Reactor instance.
|
|
81
81
|
#
|
|
82
|
-
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
83
82
|
# @param ractor_pool [RactorPool] ractor pool for HTTP parsing
|
|
83
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
84
84
|
# @param client_options [Hash] timeout configuration options
|
|
85
85
|
# @option client_options [Integer] :first_data_timeout timeout for initial data
|
|
86
86
|
# @option client_options [Integer] :chunk_data_timeout timeout for subsequent chunks
|
|
87
87
|
# @option client_options [Integer] :persistent_data_timeout timeout for keep-alive connections
|
|
88
88
|
# @return [void]
|
|
89
89
|
#
|
|
90
|
-
# @rbs (untyped
|
|
91
|
-
def initialize: (untyped
|
|
90
|
+
# @rbs (untyped ractor_pool, untyped thread_pool, client_options: Hash[Symbol, Integer]) -> void
|
|
91
|
+
def initialize: (untyped ractor_pool, untyped thread_pool, client_options: Hash[Symbol, Integer]) -> void
|
|
92
92
|
|
|
93
93
|
# Starts the reactor's main event loop in a new thread.
|
|
94
94
|
#
|
|
@@ -123,13 +123,12 @@ module Raptor
|
|
|
123
123
|
# @rbs (Hash[Symbol, untyped] state) -> void
|
|
124
124
|
def update_state: (Hash[Symbol, untyped] state) -> void
|
|
125
125
|
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
# processing. Triggers server accept re-enabling if system capacity allows.
|
|
126
|
+
# Drops the reactor's references to a client whose parsed request
|
|
127
|
+
# has been handed off to the thread pool. The socket itself is kept
|
|
128
|
+
# open so the worker can write the response.
|
|
130
129
|
#
|
|
131
130
|
# @param id [Integer] unique client identifier
|
|
132
|
-
# @return [TCPSocket, nil] the
|
|
131
|
+
# @return [TCPSocket, nil] the socket associated with `id`, if any
|
|
133
132
|
#
|
|
134
133
|
# @rbs (Integer id) -> TCPSocket?
|
|
135
134
|
def remove: (Integer id) -> TCPSocket?
|
|
@@ -202,10 +201,8 @@ module Raptor
|
|
|
202
201
|
# @rbs (Integer id) -> void
|
|
203
202
|
def close_connection: (Integer id) -> void
|
|
204
203
|
|
|
205
|
-
#
|
|
206
|
-
#
|
|
207
|
-
# Closes the registration queue and wakes up the selector to begin
|
|
208
|
-
# graceful shutdown process.
|
|
204
|
+
# Closes the registration queue and wakes the selector so the
|
|
205
|
+
# event loop drains pending work and exits.
|
|
209
206
|
#
|
|
210
207
|
# @return [void]
|
|
211
208
|
#
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
# Generated from lib/raptor/request.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Raptor
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# low-level HTTP parsing and high-level Rack application interface, handling
|
|
9
|
-
# both incomplete requests (that need more data) and complete requests
|
|
10
|
-
# (ready for application processing).
|
|
4
|
+
# Parses HTTP/1.x requests and dispatches them to the Rack
|
|
5
|
+
# application. Coordinates with the Ractor pool for parsing and
|
|
6
|
+
# with the reactor for requests that need more data before they
|
|
7
|
+
# can be handled.
|
|
11
8
|
class Request
|
|
12
9
|
BODY_BUFFER_THRESHOLD: untyped
|
|
13
10
|
|
|
@@ -21,8 +18,6 @@ module Raptor
|
|
|
21
18
|
|
|
22
19
|
MAX_KEEPALIVE_REQUESTS: ::Integer
|
|
23
20
|
|
|
24
|
-
HTTP_SCHEME: ::String
|
|
25
|
-
|
|
26
21
|
HTTP_10: ::String
|
|
27
22
|
|
|
28
23
|
HTTP_11: ::String
|
|
@@ -80,10 +75,8 @@ module Raptor
|
|
|
80
75
|
# @rbs (String buffer, ?Integer? max_size) -> [String, Symbol]
|
|
81
76
|
def self.decode_chunked: (String buffer, ?Integer? max_size) -> [ String, Symbol ]
|
|
82
77
|
|
|
83
|
-
# Writes
|
|
84
|
-
#
|
|
85
|
-
# Uses write_nonblock with `WRITE_TIMEOUT` to avoid blocking the thread
|
|
86
|
-
# indefinitely on slow clients.
|
|
78
|
+
# Writes `string` in full, retrying on partial writes. Bounded by
|
|
79
|
+
# `WRITE_TIMEOUT` so a slow client can't pin the writing thread.
|
|
87
80
|
#
|
|
88
81
|
# @param socket [TCPSocket] the socket to write to
|
|
89
82
|
# @param string [String] the data to write
|
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
# Generated from lib/raptor/server.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Raptor
|
|
4
|
-
#
|
|
4
|
+
# Accepts client connections and dispatches them into the request
|
|
5
|
+
# pipeline. Skips acceptance when the reactor backlog is high so an
|
|
6
|
+
# overloaded process leaves connections for peers that can absorb
|
|
7
|
+
# them (via shared `SO_REUSEPORT` listeners).
|
|
5
8
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is
|
|
12
|
-
# applied only to TCP sockets, and SSL handshakes are offloaded to the thread
|
|
13
|
-
# pool so a slow client cannot block the server thread.
|
|
14
|
-
#
|
|
15
|
-
# For HTTP/1.1 connections the first request is parsed inline on the server
|
|
16
|
-
# thread and dispatched directly to the thread pool, falling back to the
|
|
17
|
-
# reactor only when more data is needed. For HTTP/2 connections (negotiated
|
|
18
|
-
# via ALPN) the server sends initial SETTINGS and registers the connection
|
|
19
|
-
# with the reactor for frame processing through the ractor pool.
|
|
9
|
+
# Supports TCP, Unix, and SSL listeners. SSL handshakes are offloaded
|
|
10
|
+
# to the thread pool so a slow client can't pin the server thread.
|
|
11
|
+
# For HTTP/1.1 the first request is parsed inline and dispatched
|
|
12
|
+
# straight to the thread pool; HTTP/2 (negotiated via ALPN) is
|
|
13
|
+
# registered with the reactor for frame processing.
|
|
20
14
|
#
|
|
21
15
|
# @example
|
|
22
16
|
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
23
|
-
# reactor = Reactor.new(
|
|
17
|
+
# reactor = Reactor.new(ractor_pool, thread_pool, client_options: {})
|
|
24
18
|
# request = Request.new(app, 3000)
|
|
25
19
|
# server = Server.new(binder, reactor, thread_pool, request, client_options: { first_data_timeout: 30 })
|
|
26
20
|
# server.run
|
|
@@ -33,6 +27,10 @@ module Raptor
|
|
|
33
27
|
|
|
34
28
|
H2_PROTOCOL: ::String
|
|
35
29
|
|
|
30
|
+
DEFAULT_REMOTE_ADDR: ::String
|
|
31
|
+
|
|
32
|
+
DEFAULT_SERVER_NAME: ::String
|
|
33
|
+
|
|
36
34
|
@running: AtomicBoolean
|
|
37
35
|
|
|
38
36
|
@client_options: Hash[Symbol, untyped]
|
|
@@ -9,13 +9,17 @@ module Raptor
|
|
|
9
9
|
# assigned a fixed-size slot in the shared region.
|
|
10
10
|
#
|
|
11
11
|
# Binary layout per slot (native byte order):
|
|
12
|
-
# pid
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
12
|
+
# pid uint32 4 bytes
|
|
13
|
+
# index uint32 4 bytes
|
|
14
|
+
# phase uint32 4 bytes
|
|
15
|
+
# requests uint64 8 bytes
|
|
16
|
+
# backlog uint32 4 bytes
|
|
17
|
+
# busy_threads uint32 4 bytes
|
|
18
|
+
# thread_capacity uint32 4 bytes
|
|
19
|
+
# started_at float64 8 bytes
|
|
20
|
+
# last_checkin float64 8 bytes
|
|
21
|
+
# booted uint8 1 byte
|
|
22
|
+
# 49 bytes total
|
|
19
23
|
class Stats
|
|
20
24
|
SLOT_FORMAT: ::String
|
|
21
25
|
|
|
@@ -25,11 +29,8 @@ module Raptor
|
|
|
25
29
|
|
|
26
30
|
@mmap: untyped
|
|
27
31
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# Allocates a MAP_ANON | MAP_SHARED mmap region large enough for
|
|
31
|
-
# num_workers slots. Must be called before forking so that all
|
|
32
|
-
# worker processes share the same backing memory.
|
|
32
|
+
# Allocates the shared mmap region. Must be called before forking
|
|
33
|
+
# workers so the mapping is inherited by every child process.
|
|
33
34
|
#
|
|
34
35
|
# @param num_workers [Integer] number of worker slots to allocate
|
|
35
36
|
# @return [void]
|
|
@@ -39,21 +40,24 @@ module Raptor
|
|
|
39
40
|
|
|
40
41
|
# Writes stats for a worker slot into shared memory.
|
|
41
42
|
#
|
|
42
|
-
# @param index [Integer] slot index to write into
|
|
43
|
+
# @param index [Integer] slot index to write into; also written into the slot itself
|
|
43
44
|
# @param pid [Integer] worker process ID
|
|
45
|
+
# @param phase [Integer] cluster phase this worker was forked at
|
|
44
46
|
# @param requests [Integer] total requests handled by this worker
|
|
45
47
|
# @param backlog [Integer] current queue depth
|
|
48
|
+
# @param busy_threads [Integer] worker threads currently processing requests
|
|
49
|
+
# @param thread_capacity [Integer] worker threads configured for this worker
|
|
46
50
|
# @param started_at [Float] process start time as a Unix timestamp
|
|
47
51
|
# @param last_checkin [Float] time of last stats write as a Unix timestamp
|
|
48
52
|
# @param booted [Boolean] whether the worker has finished starting
|
|
49
53
|
# @return [void]
|
|
50
54
|
#
|
|
51
|
-
# @rbs (Integer index, pid: Integer, requests: Integer, backlog: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
52
|
-
def write: (Integer index, pid: Integer, requests: Integer, backlog: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
55
|
+
# @rbs (Integer index, pid: Integer, phase: Integer, requests: Integer, backlog: Integer, busy_threads: Integer, thread_capacity: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
56
|
+
def write: (Integer index, pid: Integer, phase: Integer, requests: Integer, backlog: Integer, busy_threads: Integer, thread_capacity: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
53
57
|
|
|
54
58
|
# Returns stats for all worker slots.
|
|
55
59
|
#
|
|
56
|
-
# @return [Array<Hash>] per-worker stat hashes with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
60
|
+
# @return [Array<Hash>] per-worker stat hashes with :pid, :index, :phase, :requests, :backlog, :busy_threads, :thread_capacity, :started_at, :last_checkin, and :booted
|
|
57
61
|
#
|
|
58
62
|
# @rbs () -> Array[Hash[Symbol, untyped]]
|
|
59
63
|
def all: () -> Array[Hash[Symbol, untyped]]
|
|
@@ -69,10 +73,10 @@ module Raptor
|
|
|
69
73
|
|
|
70
74
|
# Reads stats for a worker slot from shared memory.
|
|
71
75
|
#
|
|
72
|
-
# @param
|
|
73
|
-
# @return [Hash] stat hash with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
76
|
+
# @param slot [Integer] slot offset to read from
|
|
77
|
+
# @return [Hash] stat hash with :pid, :index, :phase, :requests, :backlog, :busy_threads, :thread_capacity, :started_at, :last_checkin, and :booted
|
|
74
78
|
#
|
|
75
|
-
# @rbs (Integer
|
|
76
|
-
def read: (Integer
|
|
79
|
+
# @rbs (Integer slot) -> Hash[Symbol, untyped]
|
|
80
|
+
def read: (Integer slot) -> Hash[Symbol, untyped]
|
|
77
81
|
end
|
|
78
82
|
end
|
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.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -103,6 +103,8 @@ extensions:
|
|
|
103
103
|
extra_rdoc_files: []
|
|
104
104
|
files:
|
|
105
105
|
- ".buildkite/pipeline.yml"
|
|
106
|
+
- ".mise.toml"
|
|
107
|
+
- Brewfile
|
|
106
108
|
- CHANGELOG.md
|
|
107
109
|
- CODE_OF_CONDUCT.md
|
|
108
110
|
- LICENSE.txt
|
|
@@ -120,6 +122,7 @@ files:
|
|
|
120
122
|
- lib/raptor/cli.rb
|
|
121
123
|
- lib/raptor/cluster.rb
|
|
122
124
|
- lib/raptor/http2.rb
|
|
125
|
+
- lib/raptor/log.rb
|
|
123
126
|
- lib/raptor/reactor.rb
|
|
124
127
|
- lib/raptor/request.rb
|
|
125
128
|
- lib/raptor/server.rb
|
|
@@ -131,6 +134,7 @@ files:
|
|
|
131
134
|
- sig/generated/raptor/cli.rbs
|
|
132
135
|
- sig/generated/raptor/cluster.rbs
|
|
133
136
|
- sig/generated/raptor/http2.rbs
|
|
137
|
+
- sig/generated/raptor/log.rbs
|
|
134
138
|
- sig/generated/raptor/reactor.rbs
|
|
135
139
|
- sig/generated/raptor/request.rbs
|
|
136
140
|
- sig/generated/raptor/server.rbs
|