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.
@@ -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 thread pools for blocking operations and ractor
9
- # pools for CPU-intensive HTTP parsing, and provides backlog metrics
10
- # that the server uses for backpressure control to prevent overload.
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(thread_pool, ractor_pool, client_options: {
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
- # Red-black tree node representing a client connection with timeout tracking.
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
- # Returns the client data stored in this timeout node.
28
+ # Semantic alias for the inherited `data` slot.
31
29
  #
32
- # @return [Hash] the client connection state data
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
- # Calculates remaining timeout duration from the current time.
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] remaining timeout in seconds, minimum 0
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
- # Compares timeout nodes by their timeout_at values for tree ordering.
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 for ordering
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 thread_pool, untyped ractor_pool, client_options: Hash[Symbol, Integer]) -> void
91
- def initialize: (untyped thread_pool, untyped ractor_pool, client_options: Hash[Symbol, Integer]) -> void
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
- # Removes a client connection from the reactor.
127
- #
128
- # Called when an HTTP request is complete and ready for application
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 removed socket, if found
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
- # Initiates reactor shutdown.
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
- # Handles HTTP request processing and Rack application integration.
5
- #
6
- # Request manages the HTTP parsing pipeline using Ractors and coordinates
7
- # with the reactor for connection state management. It bridges between the
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 a string to the socket, retrying on partial writes and flow control blocks.
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
- # High-performance HTTP server that accepts connections and dispatches them.
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
- # Server manages the main accept loop, handling incoming client connections from
7
- # bound sockets. It uses IO.select for efficient polling and implements automatic
8
- # load balancing by checking reactor backlog before accepting connections,
9
- # providing natural backpressure based on system capacity.
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(thread_pool, ractor_pool, client_options: {})
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 uint32 4 bytes
13
- # requests uint64 8 bytes
14
- # backlog uint32 4 bytes
15
- # started_at float64 8 bytes
16
- # last_checkin float64 8 bytes
17
- # booted uint8 1 byte
18
- # 33 bytes total
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
- # Creates a new Stats instance backed by anonymous shared memory.
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 index [Integer] slot index to read from
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 index) -> Hash[Symbol, untyped]
76
- def read: (Integer index) -> Hash[Symbol, untyped]
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.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