raptor 0.24.0 → 0.26.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 +34 -8
- data/AGENTS.md +25 -0
- data/CHANGELOG.md +32 -24
- data/README.md +81 -57
- data/Rakefile +10 -3
- data/docs/raptor-vs-puma.md +4 -2
- data/docs/talk.md +1 -1
- data/lib/rackup/handler/raptor.rb +19 -12
- data/lib/raptor/binder.rb +17 -5
- data/lib/raptor/cli.rb +29 -2
- data/lib/raptor/cluster.rb +15 -130
- data/lib/raptor/embedded.rb +159 -0
- data/lib/raptor/reactor.rb +120 -73
- data/lib/raptor/version.rb +1 -1
- data/lib/raptor/worker.rb +200 -0
- data/lib/raptor.rb +1 -1
- data/sig/generated/rackup/handler/raptor.rbs +8 -8
- data/sig/generated/raptor/cli.rbs +5 -0
- data/sig/generated/raptor/cluster.rbs +8 -32
- data/sig/generated/raptor/embedded.rbs +68 -0
- data/sig/generated/raptor/reactor.rbs +31 -16
- data/sig/generated/raptor/worker.rbs +77 -0
- data/sig/generated/raptor.rbs +1 -1
- metadata +7 -2
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "atomic-ruby/atomic_thread_pool"
|
|
5
|
+
require "ractor-pool"
|
|
6
|
+
|
|
7
|
+
require_relative "http1"
|
|
8
|
+
require_relative "http2"
|
|
9
|
+
require_relative "reactor"
|
|
10
|
+
require_relative "server"
|
|
11
|
+
|
|
12
|
+
module Raptor
|
|
13
|
+
# Runs the request-handling stack shared by forked and embedded servers.
|
|
14
|
+
#
|
|
15
|
+
class Worker
|
|
16
|
+
# @rbs @app: untyped
|
|
17
|
+
# @rbs @listeners: Array[TCPServer | UNIXServer | Binder::SslListener | Binder::H2cListener]
|
|
18
|
+
# @rbs @port: Integer
|
|
19
|
+
# @rbs @options: Hash[Symbol, untyped]
|
|
20
|
+
# @rbs @http1_ractors: Integer
|
|
21
|
+
# @rbs @http2_ractors: Integer
|
|
22
|
+
# @rbs @access_log_io: IO?
|
|
23
|
+
# @rbs @worker_index: Integer?
|
|
24
|
+
# @rbs @stopped: bool
|
|
25
|
+
# @rbs @http1: Http1?
|
|
26
|
+
# @rbs @http2: Http2?
|
|
27
|
+
# @rbs @http1_ractor_pool: RactorPool?
|
|
28
|
+
# @rbs @http2_ractor_pool: RactorPool?
|
|
29
|
+
# @rbs @reactor_thread: Thread?
|
|
30
|
+
# @rbs @server: Server?
|
|
31
|
+
# @rbs @server_thread: Thread?
|
|
32
|
+
|
|
33
|
+
attr_reader :requests #: Integer
|
|
34
|
+
attr_reader :reactor #: Reactor?
|
|
35
|
+
attr_reader :thread_pool #: AtomicThreadPool?
|
|
36
|
+
|
|
37
|
+
# Creates a serving stack using the supplied listeners and configuration.
|
|
38
|
+
#
|
|
39
|
+
# @rbs (untyped app, listeners: Array[TCPServer | UNIXServer | Binder::SslListener | Binder::H2cListener], port: Integer, options: Hash[Symbol, untyped], http1_ractors: Integer, http2_ractors: Integer, ?access_log_io: IO?, ?worker_index: Integer?) -> void
|
|
40
|
+
def initialize(app, listeners:, port:, options:, http1_ractors:, http2_ractors:, access_log_io: nil, worker_index: nil)
|
|
41
|
+
@app = app
|
|
42
|
+
@listeners = listeners
|
|
43
|
+
@port = port
|
|
44
|
+
@options = options
|
|
45
|
+
@http1_ractors = http1_ractors
|
|
46
|
+
@http2_ractors = http2_ractors
|
|
47
|
+
@access_log_io = access_log_io
|
|
48
|
+
@worker_index = worker_index
|
|
49
|
+
@requests = 0
|
|
50
|
+
@stopped = false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Starts the application pool, protocol parsers, reactor, and acceptor.
|
|
54
|
+
#
|
|
55
|
+
# @rbs () -> void
|
|
56
|
+
def start
|
|
57
|
+
counting_app = ->(env) {
|
|
58
|
+
@requests += 1
|
|
59
|
+
@app.call(env)
|
|
60
|
+
}
|
|
61
|
+
@thread_pool = AtomicThreadPool.new(size: @options[:threads], max_size: @options[:max_threads])
|
|
62
|
+
@http1 = Http1.new(
|
|
63
|
+
counting_app,
|
|
64
|
+
@port,
|
|
65
|
+
connection_options: @options[:connection],
|
|
66
|
+
http1_options: @options[:http1],
|
|
67
|
+
access_log_io: @access_log_io,
|
|
68
|
+
clean_thread_locals: @options[:clean_thread_locals],
|
|
69
|
+
clean_fiber_locals: @options[:clean_fiber_locals],
|
|
70
|
+
on_error: @options[:on_error]
|
|
71
|
+
)
|
|
72
|
+
@http2 = Http2.new(
|
|
73
|
+
counting_app,
|
|
74
|
+
@port,
|
|
75
|
+
connection_options: @options[:connection],
|
|
76
|
+
http2_options: @options[:http2],
|
|
77
|
+
access_log_io: @access_log_io,
|
|
78
|
+
clean_thread_locals: @options[:clean_thread_locals],
|
|
79
|
+
clean_fiber_locals: @options[:clean_fiber_locals],
|
|
80
|
+
on_error: @options[:on_error]
|
|
81
|
+
)
|
|
82
|
+
@http1_ractor_pool = RactorPool.new(
|
|
83
|
+
size: @http1_ractors,
|
|
84
|
+
worker: @http1.parser_worker,
|
|
85
|
+
name: "HTTP/1.1"
|
|
86
|
+
) do |parsed_result|
|
|
87
|
+
begin
|
|
88
|
+
@http1.handle_parsed_request(parsed_result, @reactor, @thread_pool)
|
|
89
|
+
rescue => error
|
|
90
|
+
Log.rescued_error(error)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if @listeners.any? { |listener| listener.is_a?(Binder::SslListener) || listener.is_a?(Binder::H2cListener) }
|
|
95
|
+
@http2_ractor_pool = RactorPool.new(
|
|
96
|
+
size: @http2_ractors,
|
|
97
|
+
worker: @http2.parser_worker,
|
|
98
|
+
name: "HTTP/2"
|
|
99
|
+
) do |parsed_result|
|
|
100
|
+
begin
|
|
101
|
+
@http2.handle_parsed_request(parsed_result, @reactor, @thread_pool)
|
|
102
|
+
rescue => error
|
|
103
|
+
Log.rescued_error(error)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
@reactor = Reactor.new(
|
|
109
|
+
@http1,
|
|
110
|
+
@http1_ractor_pool,
|
|
111
|
+
@http2_ractor_pool,
|
|
112
|
+
@thread_pool,
|
|
113
|
+
connection_options: @options[:connection],
|
|
114
|
+
http1_options: @options[:http1],
|
|
115
|
+
http2_options: @options[:http2]
|
|
116
|
+
)
|
|
117
|
+
@reactor_thread = @reactor.run
|
|
118
|
+
@server = Server.new(
|
|
119
|
+
@reactor,
|
|
120
|
+
@thread_pool,
|
|
121
|
+
@http1,
|
|
122
|
+
@http2,
|
|
123
|
+
connection_options: @options[:connection],
|
|
124
|
+
drain_accept_queue: @options[:drain_accept_queue],
|
|
125
|
+
listeners: @listeners,
|
|
126
|
+
worker_index: @worker_index
|
|
127
|
+
)
|
|
128
|
+
@server_thread = @server.run
|
|
129
|
+
rescue
|
|
130
|
+
shutdown
|
|
131
|
+
raise
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Returns whether both serving threads are still running.
|
|
135
|
+
#
|
|
136
|
+
# @rbs () -> bool
|
|
137
|
+
def running?
|
|
138
|
+
!!(@server_thread&.alive? && @reactor_thread&.alive?)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Waits until serving stops, propagating background thread failures.
|
|
142
|
+
#
|
|
143
|
+
# @rbs () -> void
|
|
144
|
+
def join
|
|
145
|
+
@server_thread.join(0.1) while running?
|
|
146
|
+
@server_thread.value if @server_thread && !@server_thread.alive?
|
|
147
|
+
@reactor_thread.value if @reactor_thread && !@reactor_thread.alive?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Drains requests and releases the serving threads and parser Ractors.
|
|
151
|
+
# A seed keeps its listeners open for the cluster to manage.
|
|
152
|
+
#
|
|
153
|
+
# @rbs (?close_listeners: bool) -> void
|
|
154
|
+
def shutdown(close_listeners: true)
|
|
155
|
+
return if @stopped
|
|
156
|
+
|
|
157
|
+
@stopped = true
|
|
158
|
+
begin
|
|
159
|
+
if close_listeners
|
|
160
|
+
@server&.shutdown
|
|
161
|
+
else
|
|
162
|
+
@server&.stop_accepting
|
|
163
|
+
end
|
|
164
|
+
@server_thread&.join
|
|
165
|
+
ensure
|
|
166
|
+
@http1&.shutdown
|
|
167
|
+
if @reactor_thread&.alive?
|
|
168
|
+
@http2&.shutdown(@reactor)
|
|
169
|
+
@reactor.drain_detached_bodies(@options[:worker_drain_timeout])
|
|
170
|
+
end
|
|
171
|
+
drain_thread_pool if @thread_pool
|
|
172
|
+
@reactor&.shutdown
|
|
173
|
+
begin
|
|
174
|
+
@reactor_thread&.join
|
|
175
|
+
ensure
|
|
176
|
+
@http1_ractor_pool&.shutdown
|
|
177
|
+
@http2_ractor_pool&.shutdown
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
# Waits for app work to finish within the configured drain timeout.
|
|
185
|
+
#
|
|
186
|
+
# @rbs () -> void
|
|
187
|
+
def drain_thread_pool
|
|
188
|
+
drain_thread = Thread.new do
|
|
189
|
+
Thread.current.name = "Thread Pool Drain"
|
|
190
|
+
|
|
191
|
+
@thread_pool.shutdown
|
|
192
|
+
end
|
|
193
|
+
return if drain_thread.join(@options[:worker_drain_timeout])
|
|
194
|
+
|
|
195
|
+
Log.warn "Force-killing in-flight app threads after #{@options[:worker_drain_timeout]}s drain timeout"
|
|
196
|
+
@thread_pool.instance_variable_get(:@threads).each(&:kill)
|
|
197
|
+
drain_thread.join
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
data/lib/raptor.rb
CHANGED
|
@@ -8,7 +8,7 @@ require_relative "raptor/detached_body"
|
|
|
8
8
|
#
|
|
9
9
|
# Raptor is a high-performance, preloading, multi-process, multi-threaded Ruby 4+ web server
|
|
10
10
|
# implementing Rack 3+, leveraging Ractors for parallel HTTP/1.1 and HTTP/2 request processing,
|
|
11
|
-
# native C extensions for HTTP parsing and HPACK compression, and
|
|
11
|
+
# native C extensions for HTTP parsing and HPACK compression, and io-event for non-blocking I/O.
|
|
12
12
|
#
|
|
13
13
|
module Raptor
|
|
14
14
|
end
|
|
@@ -7,16 +7,16 @@ module Rackup
|
|
|
7
7
|
module Raptor
|
|
8
8
|
DEFAULT_OPTIONS: untyped
|
|
9
9
|
|
|
10
|
-
#
|
|
10
|
+
# Serves the given Rack application using the handler options.
|
|
11
11
|
#
|
|
12
12
|
# @param app [#call] the Rack application to serve
|
|
13
13
|
# @param options [Hash] handler options provided by Rackup or the host
|
|
14
|
-
# @yield before the
|
|
15
|
-
# @yieldparam
|
|
14
|
+
# @yield before the server starts running
|
|
15
|
+
# @yieldparam server [::Raptor::Cluster, ::Raptor::Embedded] the server instance
|
|
16
16
|
# @return [void]
|
|
17
17
|
#
|
|
18
|
-
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, **untyped options) { (::Raptor::Cluster) -> void } -> void
|
|
19
|
-
def self.run: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, **untyped options) { (::Raptor::Cluster) -> void } -> void
|
|
18
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, **untyped options) { (::Raptor::Cluster | ::Raptor::Embedded) -> void } -> void
|
|
19
|
+
def self.run: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, **untyped options) { (::Raptor::Cluster | ::Raptor::Embedded) -> void } -> void
|
|
20
20
|
|
|
21
21
|
# Returns the handler-specific options surfaced by `rackup --help`.
|
|
22
22
|
#
|
|
@@ -25,17 +25,17 @@ module Rackup
|
|
|
25
25
|
# @rbs () -> Hash[String, String]
|
|
26
26
|
def self.valid_options: () -> Hash[String, String]
|
|
27
27
|
|
|
28
|
-
# Builds
|
|
28
|
+
# Builds Raptor server configuration from Rack handler options.
|
|
29
29
|
#
|
|
30
30
|
# Options not explicitly supplied by the user (per the `:user_supplied_options`
|
|
31
31
|
# key) are treated as host-provided defaults.
|
|
32
32
|
#
|
|
33
33
|
# @param app [#call] the Rack application to serve
|
|
34
34
|
# @param options [Hash] handler options provided by Rackup or the host
|
|
35
|
-
# @return [Hash{Symbol => untyped}]
|
|
35
|
+
# @return [Hash{Symbol => untyped}] server configuration
|
|
36
36
|
#
|
|
37
37
|
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
|
|
38
|
-
def self.
|
|
38
|
+
def self.build_options: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -44,10 +44,6 @@ module Raptor
|
|
|
44
44
|
# @rbs (Integer worker_count, ?cores: Integer) -> Integer
|
|
45
45
|
def self.default_http2_ractor_count: (Integer worker_count, ?cores: Integer) -> Integer
|
|
46
46
|
|
|
47
|
-
@stats_file: String?
|
|
48
|
-
|
|
49
|
-
@control_server: ControlServer?
|
|
50
|
-
|
|
51
47
|
@pid_file: String?
|
|
52
48
|
|
|
53
49
|
@stdout_file: String?
|
|
@@ -62,12 +58,18 @@ module Raptor
|
|
|
62
58
|
|
|
63
59
|
@launch_argv: Array[String]?
|
|
64
60
|
|
|
65
|
-
@on_error: (^(Hash[String, untyped]?, Exception) -> void)?
|
|
66
|
-
|
|
67
61
|
@binder: Binder
|
|
68
62
|
|
|
63
|
+
@server_port: Integer
|
|
64
|
+
|
|
65
|
+
@app: untyped
|
|
66
|
+
|
|
69
67
|
@plugins: Array[Plugin]
|
|
70
68
|
|
|
69
|
+
@control_server: ControlServer?
|
|
70
|
+
|
|
71
|
+
@stats_file: String?
|
|
72
|
+
|
|
71
73
|
@before_refork: Array[Proc]
|
|
72
74
|
|
|
73
75
|
@before_worker_shutdown: Array[Proc]
|
|
@@ -84,12 +86,6 @@ module Raptor
|
|
|
84
86
|
|
|
85
87
|
@worker_boot_timeout: Integer
|
|
86
88
|
|
|
87
|
-
@http2_options: Hash[Symbol, untyped]
|
|
88
|
-
|
|
89
|
-
@http1_options: Hash[Symbol, untyped]
|
|
90
|
-
|
|
91
|
-
@connection_options: Hash[Symbol, untyped]
|
|
92
|
-
|
|
93
89
|
@bpf_active: bool
|
|
94
90
|
|
|
95
91
|
@resp_w: IO?
|
|
@@ -130,16 +126,8 @@ module Raptor
|
|
|
130
126
|
|
|
131
127
|
@shutdown: bool
|
|
132
128
|
|
|
133
|
-
@app: untyped
|
|
134
|
-
|
|
135
|
-
@server_port: Integer
|
|
136
|
-
|
|
137
129
|
@environment: String
|
|
138
130
|
|
|
139
|
-
@clean_fiber_locals: bool
|
|
140
|
-
|
|
141
|
-
@clean_thread_locals: bool
|
|
142
|
-
|
|
143
131
|
@cpu_affinity: bool
|
|
144
132
|
|
|
145
133
|
@max_thread_count: (Integer | Float)?
|
|
@@ -152,8 +140,6 @@ module Raptor
|
|
|
152
140
|
|
|
153
141
|
@worker_count: Integer
|
|
154
142
|
|
|
155
|
-
@drain_accept_queue: bool
|
|
156
|
-
|
|
157
143
|
# Returns the cluster configuration available to plugins.
|
|
158
144
|
#
|
|
159
145
|
# @return [Hash{Symbol => untyped}]
|
|
@@ -420,16 +406,6 @@ module Raptor
|
|
|
420
406
|
# @rbs (Integer index) -> void
|
|
421
407
|
def run_seed_loop: (Integer index) -> void
|
|
422
408
|
|
|
423
|
-
# Shuts down the worker's application thread pool, force-killing the
|
|
424
|
-
# underlying threads if in-flight requests have not finished within
|
|
425
|
-
# `worker_drain_timeout` seconds.
|
|
426
|
-
#
|
|
427
|
-
# @param thread_pool [AtomicThreadPool] the worker's thread pool
|
|
428
|
-
# @return [void]
|
|
429
|
-
#
|
|
430
|
-
# @rbs (AtomicThreadPool thread_pool) -> void
|
|
431
|
-
def drain_thread_pool: (AtomicThreadPool thread_pool) -> void
|
|
432
|
-
|
|
433
409
|
# Returns a human-readable description of how a process exited.
|
|
434
410
|
#
|
|
435
411
|
# @param status [Process::Status] the exit status of the process
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Generated from lib/raptor/embedded.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Serves an existing Rack application in the caller's process without
|
|
5
|
+
# installing signal handlers or changing process-wide configuration.
|
|
6
|
+
class Embedded
|
|
7
|
+
@worker: Worker?
|
|
8
|
+
|
|
9
|
+
@binder: Binder?
|
|
10
|
+
|
|
11
|
+
@stopped: bool
|
|
12
|
+
|
|
13
|
+
@started: bool
|
|
14
|
+
|
|
15
|
+
@lifecycle_available: AtomicConditionVariable
|
|
16
|
+
|
|
17
|
+
@lifecycle_owner: Atom
|
|
18
|
+
|
|
19
|
+
@log: bool
|
|
20
|
+
|
|
21
|
+
@binds: Array[String]
|
|
22
|
+
|
|
23
|
+
@options: Hash[Symbol, untyped]
|
|
24
|
+
|
|
25
|
+
@app: untyped
|
|
26
|
+
|
|
27
|
+
attr_reader port: Integer
|
|
28
|
+
|
|
29
|
+
attr_reader addresses: Array[String]
|
|
30
|
+
|
|
31
|
+
# Creates an in-process server. A port of zero selects an available port.
|
|
32
|
+
# Thread and protocol options follow the regular server configuration.
|
|
33
|
+
# Set log to report startup information.
|
|
34
|
+
#
|
|
35
|
+
# @rbs (untyped app, ?host: String, ?port: Integer, ?log: bool, **untyped options) -> void
|
|
36
|
+
def initialize: (untyped app, ?host: String, ?port: Integer, ?log: bool, **untyped options) -> void
|
|
37
|
+
|
|
38
|
+
# Starts serving and returns once the request-handling stack is ready.
|
|
39
|
+
# Startup errors are raised in the calling thread.
|
|
40
|
+
#
|
|
41
|
+
# @rbs () -> Embedded
|
|
42
|
+
def start: () -> Embedded
|
|
43
|
+
|
|
44
|
+
# Starts serving and waits until shutdown.
|
|
45
|
+
#
|
|
46
|
+
# @rbs () -> void
|
|
47
|
+
def run: () -> void
|
|
48
|
+
|
|
49
|
+
# Drains requests and closes the server's sockets, threads, and Ractors.
|
|
50
|
+
# Calling shutdown more than once has no effect.
|
|
51
|
+
#
|
|
52
|
+
# @rbs () -> void
|
|
53
|
+
def shutdown: () -> void
|
|
54
|
+
|
|
55
|
+
# Waits for termination and propagates serving thread failures.
|
|
56
|
+
#
|
|
57
|
+
# @rbs () -> void
|
|
58
|
+
def join: () -> void
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# @rbs () -> void
|
|
63
|
+
def log_initialization: () -> void
|
|
64
|
+
|
|
65
|
+
# @rbs () { () -> untyped } -> untyped
|
|
66
|
+
def with_lifecycle: () { () -> untyped } -> untyped
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -56,8 +56,6 @@ module Raptor
|
|
|
56
56
|
|
|
57
57
|
attr_accessor closing: bool
|
|
58
58
|
|
|
59
|
-
attr_accessor monitor: NIO::Monitor?
|
|
60
|
-
|
|
61
59
|
attr_accessor timeout: TimeoutClient?
|
|
62
60
|
|
|
63
61
|
attr_reader output: Array[String]
|
|
@@ -131,13 +129,17 @@ module Raptor
|
|
|
131
129
|
def empty?: () -> bool
|
|
132
130
|
end
|
|
133
131
|
|
|
134
|
-
@io_applied: AtomicConditionVariable
|
|
135
|
-
|
|
136
132
|
@io_queue: AtomicQueue
|
|
137
133
|
|
|
138
134
|
@queue: Queue[TCPSocket]
|
|
139
135
|
|
|
140
|
-
@
|
|
136
|
+
@ready: Array[[ TCPSocket, Integer ]]
|
|
137
|
+
|
|
138
|
+
@waiters: Hash[TCPSocket, [ Fiber, Integer ]]
|
|
139
|
+
|
|
140
|
+
@wakeup: Fiber?
|
|
141
|
+
|
|
142
|
+
@selector: untyped
|
|
141
143
|
|
|
142
144
|
@http2_keepalive_timeout: Integer
|
|
143
145
|
|
|
@@ -159,6 +161,8 @@ module Raptor
|
|
|
159
161
|
|
|
160
162
|
@http1: Http1
|
|
161
163
|
|
|
164
|
+
@io_applied: AtomicConditionVariable
|
|
165
|
+
|
|
162
166
|
@timeouts: RedBlackTree[TimeoutClient]
|
|
163
167
|
|
|
164
168
|
@id_to_socket: Hash[Integer, TCPSocket]
|
|
@@ -422,6 +426,11 @@ module Raptor
|
|
|
422
426
|
|
|
423
427
|
private
|
|
424
428
|
|
|
429
|
+
# Wakes the event loop, including work queued before it starts waiting.
|
|
430
|
+
#
|
|
431
|
+
# @rbs () -> void
|
|
432
|
+
def wakeup: () -> void
|
|
433
|
+
|
|
425
434
|
# Returns whether shutdown has no registrations or writes left to drain.
|
|
426
435
|
#
|
|
427
436
|
# @return [Boolean]
|
|
@@ -603,7 +612,12 @@ module Raptor
|
|
|
603
612
|
# @return [void]
|
|
604
613
|
#
|
|
605
614
|
# @rbs (Integer id, ConnectionIO io) -> void
|
|
606
|
-
def
|
|
615
|
+
def update_interests: (Integer id, ConnectionIO io) -> void
|
|
616
|
+
|
|
617
|
+
# Waits for a connection's next readable or writable event.
|
|
618
|
+
#
|
|
619
|
+
# @rbs (TCPSocket socket, Integer events) -> void
|
|
620
|
+
def wait_for_io: (TCPSocket socket, Integer events) -> void
|
|
607
621
|
|
|
608
622
|
# Starts or refreshes one connection's non-blocking write deadline.
|
|
609
623
|
#
|
|
@@ -625,13 +639,12 @@ module Raptor
|
|
|
625
639
|
# Removes a socket from selector tracking.
|
|
626
640
|
#
|
|
627
641
|
# @param socket [TCPSocket] socket to deregister
|
|
628
|
-
# @param io [ConnectionIO, nil] connection I/O state
|
|
629
642
|
# @return [void]
|
|
630
643
|
#
|
|
631
|
-
# @rbs (TCPSocket socket
|
|
632
|
-
def deregister: (TCPSocket socket
|
|
644
|
+
# @rbs (TCPSocket socket) -> void
|
|
645
|
+
def deregister: (TCPSocket socket) -> void
|
|
633
646
|
|
|
634
|
-
# Registers a socket
|
|
647
|
+
# Registers a socket for readiness and sets up timeout tracking.
|
|
635
648
|
#
|
|
636
649
|
# @param socket [TCPSocket] the socket to register
|
|
637
650
|
# @return [void]
|
|
@@ -661,20 +674,22 @@ module Raptor
|
|
|
661
674
|
# Dispatches readable and writable events without allowing application
|
|
662
675
|
# threads to take ownership of HTTP/2 sockets.
|
|
663
676
|
#
|
|
664
|
-
# @param
|
|
677
|
+
# @param socket [TCPSocket] ready client socket
|
|
678
|
+
# @param events [Integer] readiness events
|
|
665
679
|
# @return [void]
|
|
666
680
|
#
|
|
667
|
-
# @rbs (
|
|
668
|
-
def
|
|
681
|
+
# @rbs (TCPSocket socket, Integer events) -> void
|
|
682
|
+
def handle_ready: (TCPSocket socket, Integer events) -> void
|
|
669
683
|
|
|
670
684
|
# Handles readiness for an HTTP/1.x detached response.
|
|
671
685
|
#
|
|
672
|
-
# @param
|
|
686
|
+
# @param socket [TCPSocket] ready client socket
|
|
687
|
+
# @param events [Integer] readiness events
|
|
673
688
|
# @param id [Integer] unique connection identifier
|
|
674
689
|
# @return [void]
|
|
675
690
|
#
|
|
676
|
-
# @rbs (
|
|
677
|
-
def
|
|
691
|
+
# @rbs (TCPSocket socket, Integer events, Integer id) -> void
|
|
692
|
+
def handle_http1_detached_ready: (TCPSocket socket, Integer events, Integer id) -> void
|
|
678
693
|
|
|
679
694
|
# Deregisters a readable socket and resumes its idle keep-alive
|
|
680
695
|
# connection or queues its bytes for parsing.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Generated from lib/raptor/worker.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Runs the request-handling stack shared by forked and embedded servers.
|
|
5
|
+
class Worker
|
|
6
|
+
@server_thread: Thread?
|
|
7
|
+
|
|
8
|
+
@server: Server?
|
|
9
|
+
|
|
10
|
+
@reactor_thread: Thread?
|
|
11
|
+
|
|
12
|
+
@http2_ractor_pool: RactorPool?
|
|
13
|
+
|
|
14
|
+
@http1_ractor_pool: RactorPool?
|
|
15
|
+
|
|
16
|
+
@http2: Http2?
|
|
17
|
+
|
|
18
|
+
@http1: Http1?
|
|
19
|
+
|
|
20
|
+
@stopped: bool
|
|
21
|
+
|
|
22
|
+
@worker_index: Integer?
|
|
23
|
+
|
|
24
|
+
@access_log_io: IO?
|
|
25
|
+
|
|
26
|
+
@http2_ractors: Integer
|
|
27
|
+
|
|
28
|
+
@http1_ractors: Integer
|
|
29
|
+
|
|
30
|
+
@options: Hash[Symbol, untyped]
|
|
31
|
+
|
|
32
|
+
@port: Integer
|
|
33
|
+
|
|
34
|
+
@listeners: Array[TCPServer | UNIXServer | Binder::SslListener | Binder::H2cListener]
|
|
35
|
+
|
|
36
|
+
@app: untyped
|
|
37
|
+
|
|
38
|
+
attr_reader requests: Integer
|
|
39
|
+
|
|
40
|
+
attr_reader reactor: Reactor?
|
|
41
|
+
|
|
42
|
+
attr_reader thread_pool: AtomicThreadPool?
|
|
43
|
+
|
|
44
|
+
# Creates a serving stack using the supplied listeners and configuration.
|
|
45
|
+
#
|
|
46
|
+
# @rbs (untyped app, listeners: Array[TCPServer | UNIXServer | Binder::SslListener | Binder::H2cListener], port: Integer, options: Hash[Symbol, untyped], http1_ractors: Integer, http2_ractors: Integer, ?access_log_io: IO?, ?worker_index: Integer?) -> void
|
|
47
|
+
def initialize: (untyped app, listeners: Array[TCPServer | UNIXServer | Binder::SslListener | Binder::H2cListener], port: Integer, options: Hash[Symbol, untyped], http1_ractors: Integer, http2_ractors: Integer, ?access_log_io: IO?, ?worker_index: Integer?) -> void
|
|
48
|
+
|
|
49
|
+
# Starts the application pool, protocol parsers, reactor, and acceptor.
|
|
50
|
+
#
|
|
51
|
+
# @rbs () -> void
|
|
52
|
+
def start: () -> void
|
|
53
|
+
|
|
54
|
+
# Returns whether both serving threads are still running.
|
|
55
|
+
#
|
|
56
|
+
# @rbs () -> bool
|
|
57
|
+
def running?: () -> bool
|
|
58
|
+
|
|
59
|
+
# Waits until serving stops, propagating background thread failures.
|
|
60
|
+
#
|
|
61
|
+
# @rbs () -> void
|
|
62
|
+
def join: () -> void
|
|
63
|
+
|
|
64
|
+
# Drains requests and releases the serving threads and parser Ractors.
|
|
65
|
+
# A seed keeps its listeners open for the cluster to manage.
|
|
66
|
+
#
|
|
67
|
+
# @rbs (?close_listeners: bool) -> void
|
|
68
|
+
def shutdown: (?close_listeners: bool) -> void
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Waits for app work to finish within the configured drain timeout.
|
|
73
|
+
#
|
|
74
|
+
# @rbs () -> void
|
|
75
|
+
def drain_thread_pool: () -> void
|
|
76
|
+
end
|
|
77
|
+
end
|
data/sig/generated/raptor.rbs
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Raptor is a high-performance, preloading, multi-process, multi-threaded Ruby 4+ web server
|
|
6
6
|
# implementing Rack 3+, leveraging Ractors for parallel HTTP/1.1 and HTTP/2 request processing,
|
|
7
|
-
# native C extensions for HTTP parsing and HPACK compression, and
|
|
7
|
+
# native C extensions for HTTP parsing and HPACK compression, and io-event for non-blocking I/O.
|
|
8
8
|
module Raptor
|
|
9
9
|
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.26.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -24,7 +24,7 @@ dependencies:
|
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 3.2.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: io-event
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
@@ -134,6 +134,7 @@ files:
|
|
|
134
134
|
- ".buildkite/pipeline.yml"
|
|
135
135
|
- ".dockerignore"
|
|
136
136
|
- ".mise.toml"
|
|
137
|
+
- AGENTS.md
|
|
137
138
|
- Brewfile
|
|
138
139
|
- CHANGELOG.md
|
|
139
140
|
- CODE_OF_CONDUCT.md
|
|
@@ -161,6 +162,7 @@ files:
|
|
|
161
162
|
- lib/raptor/cluster.rb
|
|
162
163
|
- lib/raptor/control_server.rb
|
|
163
164
|
- lib/raptor/detached_body.rb
|
|
165
|
+
- lib/raptor/embedded.rb
|
|
164
166
|
- lib/raptor/http.rb
|
|
165
167
|
- lib/raptor/http1.rb
|
|
166
168
|
- lib/raptor/http2.rb
|
|
@@ -173,6 +175,7 @@ files:
|
|
|
173
175
|
- lib/raptor/systemd.rb
|
|
174
176
|
- lib/raptor/thread_locals.rb
|
|
175
177
|
- lib/raptor/version.rb
|
|
178
|
+
- lib/raptor/worker.rb
|
|
176
179
|
- sig/generated/rackup/handler/raptor.rbs
|
|
177
180
|
- sig/generated/raptor.rbs
|
|
178
181
|
- sig/generated/raptor/binder.rbs
|
|
@@ -180,6 +183,7 @@ files:
|
|
|
180
183
|
- sig/generated/raptor/cluster.rbs
|
|
181
184
|
- sig/generated/raptor/control_server.rbs
|
|
182
185
|
- sig/generated/raptor/detached_body.rbs
|
|
186
|
+
- sig/generated/raptor/embedded.rbs
|
|
183
187
|
- sig/generated/raptor/http.rbs
|
|
184
188
|
- sig/generated/raptor/http1.rbs
|
|
185
189
|
- sig/generated/raptor/http2.rbs
|
|
@@ -192,6 +196,7 @@ files:
|
|
|
192
196
|
- sig/generated/raptor/systemd.rbs
|
|
193
197
|
- sig/generated/raptor/thread_locals.rbs
|
|
194
198
|
- sig/generated/raptor/version.rbs
|
|
199
|
+
- sig/generated/raptor/worker.rbs
|
|
195
200
|
homepage: https://github.com/joshuay03/raptor
|
|
196
201
|
licenses:
|
|
197
202
|
- MIT
|