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.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.yml +100 -0
- data/CHANGELOG.md +11 -0
- data/README.md +47 -31
- data/docs/raptor-vs-puma.md +81 -63
- data/ext/raptor_bpf/reuseport_select.bpf.c +8 -3
- data/ext/raptor_native/raptor_native.c +16 -2
- data/lib/raptor/binder.rb +37 -87
- data/lib/raptor/cli.rb +18 -25
- data/lib/raptor/cluster.rb +385 -82
- data/lib/raptor/http.rb +18 -0
- data/lib/raptor/http1.rb +244 -233
- data/lib/raptor/http2.rb +42 -63
- data/lib/raptor/reactor.rb +21 -52
- data/lib/raptor/reuseport_bpf.rb +27 -5
- data/lib/raptor/server.rb +24 -42
- data/lib/raptor/stats.rb +3 -8
- data/lib/raptor/systemd.rb +1 -1
- data/lib/raptor/version.rb +1 -1
- data/sig/generated/raptor/binder.rbs +34 -80
- data/sig/generated/raptor/cli.rbs +9 -25
- data/sig/generated/raptor/cluster.rbs +183 -85
- data/sig/generated/raptor/http.rbs +10 -0
- data/sig/generated/raptor/http1.rbs +129 -113
- data/sig/generated/raptor/http2.rbs +31 -48
- data/sig/generated/raptor/reactor.rbs +21 -52
- data/sig/generated/raptor/reuseport_bpf.rbs +20 -2
- data/sig/generated/raptor/server.rbs +19 -39
- data/sig/generated/raptor/stats.rbs +3 -8
- metadata +1 -1
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
# Generated from lib/raptor/binder.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Raptor
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
40
|
+
# Returns the array of bind URIs.
|
|
65
41
|
#
|
|
66
|
-
# @return [Array<String>]
|
|
42
|
+
# @return [Array<String>]
|
|
67
43
|
attr_reader bind_uris: untyped
|
|
68
44
|
|
|
69
|
-
#
|
|
45
|
+
# Returns the kernel `listen()` queue depth for TCP/SSL listeners.
|
|
70
46
|
#
|
|
71
|
-
# @return [Integer]
|
|
47
|
+
# @return [Integer]
|
|
72
48
|
attr_reader socket_backlog: untyped
|
|
73
49
|
|
|
74
|
-
#
|
|
50
|
+
# Returns the array of listening sockets.
|
|
75
51
|
#
|
|
76
|
-
# @return [Array<TCPServer, UNIXServer, SslListener>]
|
|
52
|
+
# @return [Array<TCPServer, UNIXServer, SslListener>]
|
|
77
53
|
attr_reader listeners: untyped
|
|
78
54
|
|
|
79
|
-
# Creates a new Binder
|
|
80
|
-
#
|
|
81
|
-
#
|
|
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>]
|
|
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
|
|
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]
|
|
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
|
|
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
|
|
117
|
+
# Creates fresh listeners for the given URI.
|
|
158
118
|
#
|
|
159
|
-
# @param
|
|
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 (
|
|
164
|
-
def create_listeners: (
|
|
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
|
|
126
|
+
# Reconstructs listeners for the given URI from inherited file
|
|
167
127
|
# descriptors.
|
|
168
128
|
#
|
|
169
|
-
# @param
|
|
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 (
|
|
175
|
-
def restore_listeners: (
|
|
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
|
-
#
|
|
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
|
|
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 (
|
|
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
|
|
28
|
-
#
|
|
29
|
-
#
|
|
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
|
|
59
|
-
#
|
|
60
|
-
#
|
|
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
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
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
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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
|
-
#
|
|
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
|
-
@
|
|
19
|
+
@bpf_active: bool
|
|
44
20
|
|
|
45
|
-
@
|
|
21
|
+
@server_port: Integer
|
|
46
22
|
|
|
47
|
-
@
|
|
23
|
+
@binder: Binder
|
|
48
24
|
|
|
49
|
-
@
|
|
25
|
+
@on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
|
|
50
26
|
|
|
51
|
-
@
|
|
27
|
+
@launch_argv: Array[String]?
|
|
52
28
|
|
|
53
|
-
@
|
|
29
|
+
@launch_command: String?
|
|
54
30
|
|
|
55
|
-
@
|
|
31
|
+
@access_log_io: IO?
|
|
56
32
|
|
|
57
|
-
@
|
|
33
|
+
@access_log_file: String?
|
|
58
34
|
|
|
59
35
|
@stderr_file: String?
|
|
60
36
|
|
|
61
|
-
@
|
|
37
|
+
@stdout_file: String?
|
|
62
38
|
|
|
63
|
-
@
|
|
39
|
+
@pid_file: String?
|
|
64
40
|
|
|
65
|
-
@
|
|
41
|
+
@stats_file: String?
|
|
66
42
|
|
|
67
|
-
@
|
|
43
|
+
@before_refork: Array[Proc]
|
|
68
44
|
|
|
69
|
-
@
|
|
45
|
+
@before_worker_shutdown: Array[Proc]
|
|
70
46
|
|
|
71
|
-
@
|
|
47
|
+
@before_worker_boot: Array[Proc]
|
|
72
48
|
|
|
73
|
-
@
|
|
49
|
+
@before_fork: Array[Proc]
|
|
74
50
|
|
|
75
|
-
@
|
|
51
|
+
@worker_shutdown_timeout: Integer
|
|
76
52
|
|
|
77
|
-
@
|
|
53
|
+
@worker_drain_timeout: Integer
|
|
78
54
|
|
|
79
|
-
@
|
|
55
|
+
@worker_timeout: Integer
|
|
80
56
|
|
|
81
|
-
@
|
|
57
|
+
@worker_boot_timeout: Integer
|
|
82
58
|
|
|
83
|
-
@
|
|
59
|
+
@resp_w: IO?
|
|
84
60
|
|
|
85
|
-
@
|
|
61
|
+
@resp_r: IO?
|
|
86
62
|
|
|
87
|
-
@
|
|
63
|
+
@fork_w: IO?
|
|
88
64
|
|
|
89
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
#
|
|
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, :
|
|
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
|
-
#
|
|
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
|
-
#
|
|
189
|
-
#
|
|
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
|
|
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
|
-
#
|
|
206
|
-
#
|
|
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
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
#
|
|
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
|
#
|