raptor 0.11.0 → 0.13.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.
@@ -1,30 +1,9 @@
1
1
  # Generated from lib/raptor/binder.rb with RBS::Inline
2
2
 
3
3
  module Raptor
4
- # Manages binding to network addresses and creating listening sockets.
5
- #
6
- # Binder handles parsing URI bind specifications, creating TCP, Unix, and SSL
7
- # server sockets, and managing socket options for optimal performance. It
8
- # supports binding to multiple addresses simultaneously.
9
- #
10
- # @example TCP binding
11
- # binder = Binder.new(["tcp://0.0.0.0:3000", "tcp://[::1]:3000"])
12
- # puts binder.addresses #=> ["0.0.0.0:3000", "[::1]:3000"]
13
- # binder.close
14
- #
15
- # @example Unix socket binding
16
- # binder = Binder.new(["unix:///tmp/raptor.sock"])
17
- # puts binder.addresses #=> ["/tmp/raptor.sock"]
18
- # binder.close
19
- #
20
- # @example SSL binding
21
- # binder = Binder.new(["ssl://0.0.0.0:443?cert=/path/to.crt&key=/path/to.key"])
22
- # puts binder.addresses #=> ["ssl://0.0.0.0:443"]
23
- # binder.close
24
- #
25
- # @example Localhost binding
26
- # binder = Binder.new(["tcp://localhost:8080"])
27
- # # Binds to both IPv4 and IPv6 loopback addresses
4
+ # Binds `tcp://`, `unix://`, and `ssl://` URIs to listening sockets and
5
+ # holds them for the server. Reconstructs listeners from inherited file
6
+ # descriptors when provided (systemd socket activation, hot restart).
28
7
  class Binder
29
8
  SOCKET_BACKLOG: ::Integer
30
9
 
@@ -33,11 +12,8 @@ module Raptor
33
12
  def initialize: (String scheme) -> void
34
13
  end
35
14
 
36
- # Wraps a TCPServer with an SSL context for accepting SSL connections.
37
- #
38
- # Holds both the underlying TCP server and the SSL context together so
39
- # the server thread can accept a TCP connection and then perform the SSL
40
- # handshake in a single coordinated step.
15
+ # Pairs a TCPServer with the SSL context to use for accepted
16
+ # connections.
41
17
  class SslListener < Data
42
18
  attr_reader tcp_server(): untyped
43
19
 
@@ -61,28 +37,24 @@ module Raptor
61
37
 
62
38
  @bind_uris: Array[String]
63
39
 
64
- # Array of bind URIs.
40
+ # Returns the array of bind URIs.
65
41
  #
66
- # @return [Array<String>] the bind URIs
42
+ # @return [Array<String>]
67
43
  attr_reader bind_uris: untyped
68
44
 
69
- # Kernel listen() queue depth for TCP/SSL listeners.
45
+ # Returns the kernel `listen()` queue depth for TCP/SSL listeners.
70
46
  #
71
- # @return [Integer] the socket backlog
47
+ # @return [Integer]
72
48
  attr_reader socket_backlog: untyped
73
49
 
74
- # Array of listening sockets.
50
+ # Returns the array of listening sockets.
75
51
  #
76
- # @return [Array<TCPServer, UNIXServer, SslListener>] the server sockets
52
+ # @return [Array<TCPServer, UNIXServer, SslListener>]
77
53
  attr_reader listeners: untyped
78
54
 
79
- # Creates a new Binder with the specified bind URIs.
80
- #
81
- # Parses the provided bind URIs and creates listening sockets for each one.
82
- # Supports tcp://, unix://, and ssl:// schemes. Localhost is expanded to
83
- # all available loopback addresses (both IPv4 and IPv6). When `inherited_fds`
84
- # supplies file descriptors for a URI, the listener is reconstructed from
85
- # those FDs instead of binding fresh.
55
+ # Creates a new Binder and binds each URI. `localhost` expands to both
56
+ # IPv4 and IPv6 loopback; when `inherited_fds` supplies file descriptors
57
+ # for a URI the listener is rebuilt from those instead of binding fresh.
86
58
  #
87
59
  # @param bind_uris [Array<String>] array of URI strings to bind to
88
60
  # @param socket_backlog [Integer] kernel listen() queue depth for TCP/SSL listeners
@@ -90,31 +62,21 @@ module Raptor
90
62
  # @return [void]
91
63
  # @raise [UnknownBindSchemeError] if a URI has an unsupported scheme
92
64
  #
93
- # @example
94
- # binder = Binder.new(["tcp://0.0.0.0:3000", "unix:///tmp/raptor.sock"])
95
- #
96
65
  # @rbs (Array[String] bind_uris, ?socket_backlog: Integer, ?inherited_fds: Hash[String, Array[Integer]]) -> void
97
66
  def initialize: (Array[String] bind_uris, ?socket_backlog: Integer, ?inherited_fds: Hash[String, Array[Integer]]) -> void
98
67
 
99
- # Returns the bound addresses as strings.
100
- #
101
- # TCP listeners are returned as "host:port", Unix listeners as the socket
102
- # path, and SSL listeners as "ssl://host:port".
68
+ # Returns the bound addresses as strings: TCP as `host:port`, Unix as
69
+ # the socket path, SSL as `ssl://host:port`.
103
70
  #
104
- # @return [Array<String>] address strings for each bound listener
105
- #
106
- # @example
107
- # binder.addresses #=> ["127.0.0.1:3000", "/tmp/raptor.sock", "ssl://0.0.0.0:443"]
71
+ # @return [Array<String>]
108
72
  #
109
73
  # @rbs () -> Array[String]
110
74
  def addresses: () -> Array[String]
111
75
 
112
- # Returns the port number of the first TCP or SSL listener.
113
- #
114
- # Used to populate SERVER_PORT in the Rack environment. Returns 0
115
- # if no TCP or SSL listener is configured (e.g., Unix socket only).
76
+ # Returns the port of the first TCP or SSL listener, or 0 when none
77
+ # is configured.
116
78
  #
117
- # @return [Integer] the port number, or 0 if no TCP listener exists
79
+ # @return [Integer]
118
80
  #
119
81
  # @rbs () -> Integer
120
82
  def server_port: () -> Integer
@@ -126,9 +88,7 @@ module Raptor
126
88
  # @rbs () -> void
127
89
  def close: () -> void
128
90
 
129
- # Returns the file descriptors of every listener, grouped by the bind URI
130
- # they were created from. The result is the payload to hand to a successor
131
- # process via the `inherited_fds:` constructor argument.
91
+ # Returns the file descriptors of every listener, grouped by bind URI.
132
92
  #
133
93
  # @return [Hash{String => Array<Integer>}]
134
94
  #
@@ -154,25 +114,25 @@ module Raptor
154
114
  # @rbs () -> void
155
115
  def parse: () -> void
156
116
 
157
- # Creates fresh listeners for the given bind URI.
117
+ # Creates fresh listeners for the given URI.
158
118
  #
159
- # @param bind_uri [String] the URI to bind
119
+ # @param uri [URI] the parsed bind URI
160
120
  # @return [Array<TCPServer, UNIXServer, SslListener>]
161
121
  # @raise [UnknownBindSchemeError] if the URI scheme is not supported
162
122
  #
163
- # @rbs (String bind_uri) -> Array[TCPServer | UNIXServer | SslListener]
164
- def create_listeners: (String bind_uri) -> Array[TCPServer | UNIXServer | SslListener]
123
+ # @rbs (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener]
124
+ def create_listeners: (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener]
165
125
 
166
- # Reconstructs listeners for the given bind URI from inherited file
126
+ # Reconstructs listeners for the given URI from inherited file
167
127
  # descriptors.
168
128
  #
169
- # @param bind_uri [String] the URI the FDs were bound to
129
+ # @param uri [URI] the parsed bind URI the FDs were bound to
170
130
  # @param filenos [Array<Integer>] file descriptors to wrap
171
131
  # @return [Array<TCPServer, UNIXServer, SslListener>]
172
132
  # @raise [UnknownBindSchemeError] if the URI scheme is not supported
173
133
  #
174
- # @rbs (String bind_uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
175
- def restore_listeners: (String bind_uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
134
+ # @rbs (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
135
+ def restore_listeners: (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
176
136
 
177
137
  # Creates TCP server sockets for the given host and port.
178
138
  #
@@ -183,11 +143,9 @@ module Raptor
183
143
  # @rbs (String? host, Integer? port) -> Array[TCPServer]
184
144
  def create_tcp_listeners: (String? host, Integer? port) -> Array[TCPServer]
185
145
 
186
- # Creates a Unix domain server socket at the given path.
187
- #
188
- # Removes stale socket files left by crashed processes (when the socket
189
- # is not currently in use). Registers an at_exit hook to clean up the
190
- # socket file on normal process exit.
146
+ # Creates a Unix domain server socket at the given path. Removes stale
147
+ # socket files left by crashed processes, and cleans the file up on
148
+ # the master's clean exit.
191
149
  #
192
150
  # @param path [String] filesystem path for the Unix socket
193
151
  # @return [Array<UNIXServer>] array containing the created Unix server socket
@@ -206,15 +164,11 @@ module Raptor
206
164
  # @rbs (String path) -> void
207
165
  def register_unix_socket_cleanup: (String path) -> void
208
166
 
209
- # Creates SSL server sockets for the given host, port, and SSL parameters.
210
- #
211
- # Wraps each TCP listener with an SSL context to produce SslListener objects.
212
- # The ssl_params hash must include "cert" and "key" entries pointing to the
213
- # certificate and private key files respectively.
167
+ # Creates SSL server sockets for the given host and port.
214
168
  #
215
169
  # @param host [String, nil] hostname or IP address to bind to
216
170
  # @param port [Integer, nil] port number to bind to
217
- # @param ssl_params [Hash<String, String>] SSL options ("cert" and "key" paths)
171
+ # @param ssl_params [Hash<String, String>] SSL options (`cert` and `key` file paths)
218
172
  # @return [Array<SslListener>] array containing the created SSL listener(s)
219
173
  #
220
174
  # @rbs (String? host, Integer? port, Hash[String, String] ssl_params) -> Array[SslListener]
@@ -24,11 +24,9 @@ module Raptor
24
24
 
25
25
  DEFAULT_CONFIG_PATHS: untyped
26
26
 
27
- # Loads a configuration file and returns the hash it evaluates to.
28
- #
29
- # The file is evaluated at the top level so constants like `Raptor::*` resolve
30
- # the same as in a regular Ruby script. The final expression must be a Hash
31
- # of cluster options (the same keys accepted by {Raptor::Cluster#initialize}).
27
+ # Loads a Ruby config file and returns the options hash it evaluates
28
+ # to. Evaluated at the top level so `Raptor::*` constants resolve the
29
+ # same as in a regular script.
32
30
  #
33
31
  # @param path [String] path to a Ruby file that evaluates to a Hash
34
32
  # @return [Hash{Symbol => untyped}] cluster options
@@ -40,9 +38,6 @@ module Raptor
40
38
  # Returns the first existing path in {DEFAULT_CONFIG_PATHS} resolved
41
39
  # against `root`, or nil if none exist.
42
40
  #
43
- # Used to pick up a project-local config file when no `-c`/`--config`
44
- # flag was supplied.
45
- #
46
41
  # @param root [String] directory to resolve the default paths against
47
42
  # @return [String, nil] the config path, or nil if no default file exists
48
43
  #
@@ -55,22 +50,14 @@ module Raptor
55
50
 
56
51
  @parser: OptionParser
57
52
 
58
- # Creates a new CLI instance and parses command-line arguments.
59
- #
60
- # Parses the provided command-line arguments and configures the server
61
- # options accordingly. A rackup file can be provided as the first
62
- # positional argument (defaults to config.ru).
53
+ # Creates a new CLI instance from `argv`. A rackup file may be given
54
+ # as the first positional argument; every other value is parsed as a
55
+ # flag.
63
56
  #
64
57
  # @param argv [Array<String>] command-line arguments to parse
65
58
  # @return [void]
66
59
  # @raise [OptionParser::ParseError] if invalid options are provided
67
60
  #
68
- # @example With rackup file
69
- # cli = CLI.new(["my_app.ru", "-w", "4"])
70
- #
71
- # @example With options only
72
- # cli = CLI.new(["-t", "8", "-r", "2"])
73
- #
74
61
  # @rbs (Array[String] argv) -> void
75
62
  def initialize: (Array[String] argv) -> void
76
63
 
@@ -90,12 +77,9 @@ module Raptor
90
77
  # @rbs () -> void
91
78
  def run_stats: () -> void
92
79
 
93
- # Scans argv for a `-c`/`--config` flag and returns the configured path.
94
- #
95
- # The pre-scan runs before the main OptionParser pass so the config file
96
- # can be applied as a base layer that CLI args then override. All four
97
- # OptionParser-accepted forms (`-c PATH`, `-cPATH`, `--config PATH`,
98
- # `--config=PATH`) are recognized.
80
+ # Returns the path from a `-c`/`--config` flag in `argv`, recognising
81
+ # all four OptionParser-accepted forms (`-c PATH`, `-cPATH`,
82
+ # `--config PATH`, `--config=PATH`).
99
83
  #
100
84
  # @param argv [Array<String>] command-line arguments to scan
101
85
  # @return [String, nil] the config path, or nil if no flag was supplied
@@ -1,38 +1,14 @@
1
1
  # Generated from lib/raptor/cluster.rb with RBS::Inline
2
2
 
3
3
  module Raptor
4
- # Multi-process web server cluster with advanced concurrency architecture.
5
- #
6
- # Cluster manages multiple worker processes, each running a complete server
7
- # stack including a ractor pool for HTTP parsing, a thread pool for
8
- # application processing, plus dedicated reactor and server threads. It
9
- # handles process forking, signal management, graceful shutdown, and
10
- # automatic worker restart when a worker process unexpectedly exits.
11
- #
12
- # The architecture provides horizontal scaling through processes while
13
- # maintaining efficient I/O and CPU utilization within each process
14
- # through the combination of ractor-based parsing and thread pools on
15
- # top of NIO reactors.
16
- #
17
- # Flow per worker process:
18
- # 1. Server continuously accepts connections but skips acceptance when backlog is high
19
- # 2. Reactor manages I/O multiplexing and provides backlog metrics for load control
20
- # 3. Ractor pool handles CPU-intensive HTTP parsing in parallel
21
- # 4. Thread pool processes Rack applications and handles response writing
22
- # 5. Natural load balancing occurs through backpressure-based acceptance control
23
- #
24
- # @example Basic usage
25
- # options = {
26
- # workers: 4, ractors: 2, threads: 8,
27
- # binds: ["tcp://0.0.0.0:3000"],
28
- # rackup: "config.ru",
29
- # connection: { first_data_timeout: 30, chunk_data_timeout: 10 }
30
- # }
31
- # Cluster.run(options)
4
+ # Forks and supervises worker processes. Handles graceful shutdown on
5
+ # `INT` and `TERM`, phased restart on `USR1`, hot restart on `USR2`,
6
+ # and (on Linux) refork on `URG`. Restarts workers that exit
7
+ # unexpectedly or stop checking in.
32
8
  class Cluster
33
9
  INHERITED_FDS_ENV: ::String
34
10
 
35
- # Convenience method to create and run a cluster with the given options.
11
+ # Creates and runs a cluster with the given options.
36
12
  #
37
13
  # @param options [Hash] cluster configuration options
38
14
  # @return [void]
@@ -40,57 +16,85 @@ module Raptor
40
16
  # @rbs (Hash[Symbol, untyped] options) -> void
41
17
  def self.run: (Hash[Symbol, untyped] options) -> void
42
18
 
43
- @http2_options: Hash[Symbol, untyped]
19
+ @bpf_active: bool
44
20
 
45
- @worker_boot_timeout: Integer
21
+ @server_port: Integer
46
22
 
47
- @worker_timeout: Integer
23
+ @binder: Binder
48
24
 
49
- @worker_drain_timeout: Integer
25
+ @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
50
26
 
51
- @worker_shutdown_timeout: Integer
27
+ @launch_argv: Array[String]?
52
28
 
53
- @stats_file: String?
29
+ @launch_command: String?
54
30
 
55
- @pid_file: String?
31
+ @access_log_io: IO?
56
32
 
57
- @stdout_file: String?
33
+ @access_log_file: String?
58
34
 
59
35
  @stderr_file: String?
60
36
 
61
- @access_log_file: String?
37
+ @stdout_file: String?
62
38
 
63
- @access_log_io: IO?
39
+ @pid_file: String?
64
40
 
65
- @launch_command: String?
41
+ @stats_file: String?
66
42
 
67
- @launch_argv: Array[String]?
43
+ @before_refork: Array[Proc]
68
44
 
69
- @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
45
+ @before_worker_shutdown: Array[Proc]
70
46
 
71
- @binder: Binder
47
+ @before_worker_boot: Array[Proc]
72
48
 
73
- @server_port: Integer
49
+ @before_fork: Array[Proc]
74
50
 
75
- @app: untyped
51
+ @worker_shutdown_timeout: Integer
76
52
 
77
- @shutdown: bool
53
+ @worker_drain_timeout: Integer
78
54
 
79
- @workers: Hash[Integer, Integer]
55
+ @worker_timeout: Integer
80
56
 
81
- @timed_out: Set[Integer]
57
+ @worker_boot_timeout: Integer
82
58
 
83
- @stats: Stats
59
+ @resp_w: IO?
84
60
 
85
- @phase: Integer
61
+ @resp_r: IO?
86
62
 
87
- @phased_restart_requested: bool
63
+ @fork_w: IO?
88
64
 
89
- @phased_restarting: bool
65
+ @fork_r: IO?
66
+
67
+ @seed_vacated_index: Integer?
68
+
69
+ @seed_ready: bool
70
+
71
+ @seed_pid: Integer?
72
+
73
+ @refork_threshold_idx: Integer
74
+
75
+ @refork_requested: bool
76
+
77
+ @refork_thresholds: Array[Integer]
90
78
 
91
79
  @hot_restart_requested: bool
92
80
 
93
- @bpf_active: bool
81
+ @phased_restarting: bool
82
+
83
+ @phased_restart_requested: bool
84
+
85
+ @phase: Integer
86
+
87
+ @stats: Stats
88
+
89
+ @timed_out: Set[Integer]
90
+
91
+ @workers: Hash[Integer, Integer]
92
+
93
+ @shutdown: bool
94
+
95
+ @app: untyped
96
+
97
+ @http2_options: Hash[Symbol, untyped]
94
98
 
95
99
  @http1_options: Hash[Symbol, untyped]
96
100
 
@@ -106,11 +110,7 @@ module Raptor
106
110
 
107
111
  @drain_accept_queue: bool
108
112
 
109
- # Creates a new Cluster with the specified configuration.
110
- #
111
- # Initializes the cluster with worker, ractor, and thread counts,
112
- # sets up network binding, loads the Rack application, and prepares
113
- # for multi-process operation.
113
+ # Creates a new Cluster with the given options.
114
114
  #
115
115
  # @param options [Hash] cluster configuration options
116
116
  # @option options [Array<String>] :binds array of bind URIs
@@ -130,6 +130,11 @@ module Raptor
130
130
  # @option options [Integer] :worker_timeout seconds to wait for a booted worker to check in before killing it
131
131
  # @option options [Integer] :worker_drain_timeout seconds a worker waits for in-flight requests during shutdown before force-killing app threads
132
132
  # @option options [Integer] :worker_shutdown_timeout seconds to wait for graceful worker exit before force-killing
133
+ # @option options [Integer, Array<Integer>, nil] :refork_after request-count threshold(s) at which a warm worker is promoted to a fork source for phased refork; nil or 0 disables. Requires `PR_SET_CHILD_SUBREAPER` (Linux)
134
+ # @option options [Array<Proc>] :before_fork procs called in the master before every worker fork
135
+ # @option options [Array<Proc>] :before_worker_boot procs called in each worker before it begins serving
136
+ # @option options [Array<Proc>] :before_worker_shutdown procs called in each worker before its graceful shutdown
137
+ # @option options [Array<Proc>] :before_refork procs called in a worker before it transitions to a seed
133
138
  # @option options [String, nil] :stats_file path to write per-worker stats JSON, or nil to disable
134
139
  # @option options [String, nil] :pid_file path to write the master PID to, or nil to disable
135
140
  # @option options [String, nil] :stdout_file path to redirect stdout to, reopened on SIGHUP, or nil to disable
@@ -143,20 +148,7 @@ module Raptor
143
148
  # @rbs (Hash[Symbol, untyped] options) -> void
144
149
  def initialize: (Hash[Symbol, untyped] options) -> void
145
150
 
146
- # Starts the multi-process cluster and manages worker processes.
147
- #
148
- # Forks the configured number of worker processes and monitors them,
149
- # restarting any that exit unexpectedly or stop checking in. Handles
150
- # graceful shutdown via INT or TERM signals, phased restart via USR1,
151
- # and hot restart via USR2.
152
- #
153
- # Each worker process includes:
154
- # - 1 server thread (continuously accepts connections with backpressure control)
155
- # - 1 reactor thread (I/O multiplexing, timeout handling, backlog monitoring)
156
- # - N pipeline ractors (parallel HTTP parsing)
157
- # - 1 pipeline collector thread (coordinates parsing results)
158
- # - M worker threads (Rack application processing and response writing)
159
- # - 1 stats thread (writes per-worker metrics to shared memory every second)
151
+ # Runs the cluster until a graceful shutdown is signalled.
160
152
  #
161
153
  # @return [void]
162
154
  #
@@ -166,7 +158,8 @@ module Raptor
166
158
  # Returns stats for all worker processes.
167
159
  #
168
160
  # @return [Array<Hash>] array of per-worker stat hashes, each containing
169
- # :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
161
+ # :pid, :index, :phase, :requests, :backlog, :busy_threads,
162
+ # :thread_capacity, :started_at, :last_checkin, and :booted
170
163
  #
171
164
  # @rbs () -> Array[Hash[Symbol, untyped]]
172
165
  def stats: () -> Array[Hash[Symbol, untyped]]
@@ -175,8 +168,7 @@ module Raptor
175
168
 
176
169
  # Returns the inherited-FDs hash for a systemd socket-activation handoff,
177
170
  # pairing each bind URI with the FD systemd passed at the same index.
178
- # The activation is skipped (with a warning) when the FD count doesn't
179
- # match the number of bind URIs.
171
+ # Returns an empty hash when the FD count doesn't match the bind count.
180
172
  #
181
173
  # @param bind_uris [Array<String>] the configured bind URIs
182
174
  # @param filenos [Array<Integer>] file descriptors passed by systemd
@@ -185,8 +177,18 @@ module Raptor
185
177
  # @rbs (Array[String] bind_uris, Array[Integer] filenos) -> Hash[String, Array[Integer]]
186
178
  def pair_systemd_fds: (Array[String] bind_uris, Array[Integer] filenos) -> Hash[String, Array[Integer]]
187
179
 
188
- # Forks a new worker process and registers it at the given index.
189
- # The worker inherits the cluster's current phase.
180
+ # Normalises the `refork_after` option into a sorted array of positive
181
+ # thresholds. Accepts nil, 0, an Integer, or an Array<Integer>; anything
182
+ # else falls back to an empty array (feature disabled).
183
+ #
184
+ # @param value [Integer, Array<Integer>, nil] the raw option value
185
+ # @return [Array<Integer>]
186
+ #
187
+ # @rbs (untyped value) -> Array[Integer]
188
+ def normalize_refork_thresholds: (untyped value) -> Array[Integer]
189
+
190
+ # Forks a new worker process and registers it at the given index,
191
+ # forking from the seed when one is active and off the master otherwise.
190
192
  #
191
193
  # @param index [Integer] slot index for this worker in the stats region
192
194
  # @return [void]
@@ -194,16 +196,87 @@ module Raptor
194
196
  # @rbs (Integer index) -> void
195
197
  def spawn_worker: (Integer index) -> void
196
198
 
199
+ # Asks the seed to fork a new worker at the given index, returning the
200
+ # child pid, or nil when the seed doesn't respond in time.
201
+ #
202
+ # @param index [Integer] slot index for the new worker
203
+ # @return [Integer, nil] the forked worker's pid, or nil on failure
204
+ #
205
+ # @rbs (Integer index) -> Integer?
206
+ def spawn_worker_via_seed: (Integer index) -> Integer?
207
+
208
+ # Checks whether a process with the given pid is currently alive.
209
+ #
210
+ # @param pid [Integer] the pid to probe
211
+ # @return [Boolean] true if the process exists
212
+ #
213
+ # @rbs (Integer pid) -> bool
214
+ def pid_alive?: (Integer pid) -> bool
215
+
197
216
  # Reaps any worker processes that have exited, respawning each one
198
217
  # unless the cluster is shutting down.
199
218
  #
200
- # @return [Symbol] :no_children when there are no remaining children, otherwise :reaped
219
+ # @return [Symbol] :no_children when nothing is left to supervise, otherwise :reaped
201
220
  #
202
221
  # @rbs () -> Symbol
203
222
  def reap_workers: () -> Symbol
204
223
 
205
- # Stops every worker, escalating from TERM to KILL if any fail to
206
- # exit within `worker_shutdown_timeout`.
224
+ # Records a reaped pid, respawning its worker slot unless the cluster
225
+ # is shutting down. Clears the seed reference when the seed exits.
226
+ #
227
+ # @param pid [Integer] the reaped pid
228
+ # @param status [Process::Status] the exit status
229
+ # @return [void]
230
+ #
231
+ # @rbs (Integer pid, Process::Status status) -> void
232
+ def reap_pid: (Integer pid, Process::Status status) -> void
233
+
234
+ # Promotes the most-experienced worker to a seed and starts a phased
235
+ # refork when the next `refork_after` threshold is crossed or a manual
236
+ # refork was requested via `SIGURG`.
237
+ #
238
+ # @return [void]
239
+ #
240
+ # @rbs () -> void
241
+ def check_refork_trigger: () -> void
242
+
243
+ # Picks the most-experienced booted worker in the current phase,
244
+ # returning its slot index and its request count. Returns nil when
245
+ # no worker qualifies.
246
+ #
247
+ # @return [Array<Integer>, nil]
248
+ #
249
+ # @rbs () -> Array[Integer]?
250
+ def pick_refork_candidate: () -> Array[Integer]?
251
+
252
+ # Retires the current seed and promotes the given worker into its place,
253
+ # queueing a phased refork for the remaining workers.
254
+ #
255
+ # @param index [Integer] slot index of the worker to promote
256
+ # @return [void]
257
+ #
258
+ # @rbs (Integer index) -> void
259
+ def promote_worker_to_seed: (Integer index) -> void
260
+
261
+ # Terminates the currently-active seed process, if any, and waits for
262
+ # it to exit. Its seed-forked workers stay attached to the master and
263
+ # keep serving.
264
+ #
265
+ # @return [void]
266
+ #
267
+ # @rbs () -> void
268
+ def retire_current_seed: () -> void
269
+
270
+ # Records the seed's readiness when its ready marker has arrived.
271
+ # Non-blocking.
272
+ #
273
+ # @return [void]
274
+ #
275
+ # @rbs () -> void
276
+ def poll_seed_ready: () -> void
277
+
278
+ # Stops every worker (and the seed if one is active), escalating
279
+ # from TERM to KILL if any fail to exit within `worker_shutdown_timeout`.
207
280
  #
208
281
  # @return [void]
209
282
  #
@@ -229,6 +302,23 @@ module Raptor
229
302
  # @rbs () -> void
230
303
  def perform_phased_restart: () -> void
231
304
 
305
+ # Blocks until the freshly-promoted seed has signalled readiness,
306
+ # or times out and clears the seed reference. No-op when no seed is
307
+ # being promoted.
308
+ #
309
+ # @return [void]
310
+ #
311
+ # @rbs () -> void
312
+ def wait_for_seed_ready: () -> void
313
+
314
+ # Spawns a replacement worker for the slot the seed vacated when
315
+ # it was promoted, returning the slot index it filled.
316
+ #
317
+ # @return [Integer, nil] the filled slot index, or nil if none was vacated
318
+ #
319
+ # @rbs () -> Integer?
320
+ def fill_vacated_seed_slot: () -> Integer?
321
+
232
322
  # Re-execs the master process with a fresh boot of the same Raptor
233
323
  # invocation, handing the new master its listening sockets so accepted
234
324
  # connections continue to be served across the swap.
@@ -238,11 +328,10 @@ module Raptor
238
328
  # @rbs () -> void
239
329
  def perform_hot_restart: () -> void
240
330
 
241
- # Runs the full server stack inside a worker process.
242
- #
243
- # Sets up and coordinates the reactor, server, ractor pool, thread pool,
244
- # and stats thread, running until a shutdown signal is received or a
245
- # critical component fails.
331
+ # Runs a worker process's full server stack until a shutdown signal is
332
+ # received or a critical component fails. On `SIGURG` the worker drains
333
+ # and transitions into a seed loop that forks replacement workers on
334
+ # master's request.
246
335
  #
247
336
  # @param index [Integer] slot index for this worker in the stats region
248
337
  # @param phase [Integer] the cluster phase this worker was forked at
@@ -251,6 +340,15 @@ module Raptor
251
340
  # @rbs (Integer index, Integer phase) -> void
252
341
  def run_worker: (Integer index, Integer phase) -> void
253
342
 
343
+ # Runs the seed's fork loop, forking a replacement worker for each
344
+ # slot index the master asks for.
345
+ #
346
+ # @param index [Integer] the seed's original slot index
347
+ # @return [void]
348
+ #
349
+ # @rbs (Integer index) -> void
350
+ def run_seed_loop: (Integer index) -> void
351
+
254
352
  # Shuts down the worker's application thread pool, force-killing the
255
353
  # underlying threads if in-flight requests have not finished within
256
354
  # `worker_drain_timeout` seconds.
@@ -51,6 +51,16 @@ module Raptor
51
51
  # @rbs (TCPSocket socket, Array[String] strings, ?timeout: Integer) -> void
52
52
  def self.socket_writev: (TCPSocket socket, Array[String] strings, ?timeout: Integer) -> void
53
53
 
54
+ # Returns a Ractor-safe proc that routes each pipeline task to the
55
+ # HTTP/1.x or HTTP/2 handler based on the state hash's `:protocol` key.
56
+ #
57
+ # @param env_template [Hash] the Rack env template to seed each HTTP/1.x request with
58
+ # @param max_body_size [Integer, nil] byte limit for HTTP/1.x request bodies, or nil for no limit
59
+ # @return [Proc]
60
+ #
61
+ # @rbs (Hash[String, untyped] env_template, Integer? max_body_size) -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
62
+ def self.parser_worker: (Hash[String, untyped] env_template, Integer? max_body_size) -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
63
+
54
64
  # Writes a Common Log Format entry to `io`. Write failures are silently
55
65
  # ignored.
56
66
  #