raptor 0.19.0 → 0.20.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,38 @@
1
+ # rbs_inline: enabled
2
+ # frozen_string_literal: true
3
+
4
+ module Raptor
5
+ # Owns Raptor's reusable per-thread values and clears application thread
6
+ # locals after each request.
7
+ #
8
+ module ThreadLocals
9
+ PRESERVED_KEYS = [
10
+ :raptor_http_parser,
11
+ :raptor_read_buffer,
12
+ :raptor_response_buffer,
13
+ ].freeze
14
+
15
+ # Returns a reusable value stored on the current thread.
16
+ #
17
+ # @return [Object]
18
+ #
19
+ # @rbs (Symbol key) { () -> untyped } -> untyped
20
+ def self.fetch(key)
21
+ thread = Thread.current
22
+ thread.thread_variable_get(key) || thread.thread_variable_set(key, yield)
23
+ end
24
+
25
+ # Clears application-owned true thread locals while retaining Raptor's
26
+ # reusable per-thread values.
27
+ #
28
+ # @return [void]
29
+ #
30
+ # @rbs () -> void
31
+ def self.clear
32
+ thread = Thread.current
33
+ thread.thread_variables.each do |key|
34
+ thread.thread_variable_set(key, nil) unless PRESERVED_KEYS.include?(key)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Raptor
5
- VERSION = "0.19.0"
5
+ VERSION = "0.20.0"
6
6
  end
@@ -106,6 +106,14 @@ module Raptor
106
106
  # @rbs (String? path) -> void
107
107
  def apply_config_file: (String? path) -> void
108
108
 
109
+ # Applies worker and thread settings from the environment. Explicit CLI
110
+ # options are parsed afterwards and take precedence.
111
+ #
112
+ # @return [void]
113
+ #
114
+ # @rbs () -> void
115
+ def apply_environment: () -> void
116
+
109
117
  # Creates the OptionParser instance with all supported command-line options.
110
118
  #
111
119
  # @return [OptionParser] configured option parser
@@ -44,27 +44,27 @@ 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
- @server_port: Integer
48
-
49
- @binder: Binder
47
+ @stats_file: String?
50
48
 
51
- @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
49
+ @control_server: ControlServer?
52
50
 
53
- @launch_argv: Array[String]?
51
+ @pid_file: String?
54
52
 
55
- @launch_command: String?
53
+ @stdout_file: String?
56
54
 
57
- @access_log_io: IO?
55
+ @stderr_file: String?
58
56
 
59
57
  @access_log_file: String?
60
58
 
61
- @stderr_file: String?
59
+ @access_log_io: IO?
62
60
 
63
- @stdout_file: String?
61
+ @launch_command: String?
64
62
 
65
- @pid_file: String?
63
+ @launch_argv: Array[String]?
66
64
 
67
- @stats_file: String?
65
+ @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
66
+
67
+ @binder: Binder
68
68
 
69
69
  @before_refork: Array[Proc]
70
70
 
@@ -84,6 +84,10 @@ module Raptor
84
84
 
85
85
  @http2_options: Hash[Symbol, untyped]
86
86
 
87
+ @http1_options: Hash[Symbol, untyped]
88
+
89
+ @connection_options: Hash[Symbol, untyped]
90
+
87
91
  @bpf_active: bool
88
92
 
89
93
  @resp_w: IO?
@@ -114,6 +118,8 @@ module Raptor
114
118
 
115
119
  @phase: Integer
116
120
 
121
+ @started_at: Float
122
+
117
123
  @stats: Stats
118
124
 
119
125
  @timed_out: Set[Integer]
@@ -124,12 +130,16 @@ module Raptor
124
130
 
125
131
  @app: untyped
126
132
 
127
- @http1_options: Hash[Symbol, untyped]
128
-
129
- @connection_options: Hash[Symbol, untyped]
133
+ @server_port: Integer
130
134
 
131
135
  @environment: String
132
136
 
137
+ @clean_fiber_locals: bool
138
+
139
+ @clean_thread_locals: bool
140
+
141
+ @cpu_affinity: bool
142
+
133
143
  @max_thread_count: (Integer | Float)?
134
144
 
135
145
  @thread_count: Integer
@@ -151,6 +161,9 @@ module Raptor
151
161
  # @option options [Integer] :workers number of worker processes
152
162
  # @option options [Integer] :threads number of threads per worker process
153
163
  # @option options [Integer, Float] :max_threads maximum number of threads per worker process, or `Float::INFINITY` for no limit
164
+ # @option options [Boolean] :cpu_affinity whether to pin each worker to a CPU
165
+ # @option options [Boolean] :clean_thread_locals whether to clear application thread locals after each request
166
+ # @option options [Boolean] :clean_fiber_locals whether to process each request in a fresh Fiber
154
167
  # @option options [#call] :app pre-built Rack application
155
168
  # @option options [String] :rackup path to Rack configuration file
156
169
  # @option options [String, nil] :chdir directory to change to before loading the Rack application, or nil to leave the working directory unchanged
@@ -164,10 +177,11 @@ module Raptor
164
177
  # @option options [Integer] :worker_shutdown_timeout seconds to wait for graceful worker exit before force-killing
165
178
  # @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)
166
179
  # @option options [Array<Proc>] :before_fork procs called in the master before every worker fork
167
- # @option options [Array<Proc>] :before_worker_boot procs called in each worker before it begins serving
168
- # @option options [Array<Proc>] :before_worker_shutdown procs called in each worker before its graceful shutdown
180
+ # @option options [Array<Proc>] :before_worker_boot procs called with the worker index before it begins serving
181
+ # @option options [Array<Proc>] :before_worker_shutdown procs called with the worker index before its graceful shutdown
169
182
  # @option options [Array<Proc>] :before_refork procs called in a worker before it transitions to a seed
170
183
  # @option options [String, nil] :stats_file path to write per-worker stats JSON, or nil to disable
184
+ # @option options [String, nil] :control_url `unix://` URL serving cluster stats, or nil to disable
171
185
  # @option options [String, nil] :pid_file path to write the master PID to, or nil to disable
172
186
  # @option options [String, nil] :stdout_file path to redirect stdout to, reopened on SIGHUP, or nil to disable
173
187
  # @option options [String, nil] :stderr_file path to redirect stderr to, reopened on SIGHUP, or nil to disable
@@ -196,8 +210,20 @@ module Raptor
196
210
  # @rbs () -> Array[Hash[Symbol, untyped]]
197
211
  def stats: () -> Array[Hash[Symbol, untyped]]
198
212
 
213
+ # Returns cluster statistics for the control server.
214
+ # For an adaptive pool, `max_threads` is the number of threads currently
215
+ # running so utilization reflects the capacity available at that moment.
216
+ #
217
+ # @return [Hash] cluster statistics
218
+ #
219
+ # @rbs () -> Hash[Symbol, untyped]
220
+ def stats_hash: () -> Hash[Symbol, untyped]
221
+
199
222
  private
200
223
 
224
+ # @rbs (Float timestamp) -> String
225
+ def timestamp: (Float timestamp) -> String
226
+
201
227
  # Returns the inherited-FDs hash for a systemd socket-activation handoff,
202
228
  # pairing each bind URI with the FD systemd passed at the same index.
203
229
  # Returns an empty hash when the FD count doesn't match the bind count.
@@ -0,0 +1,70 @@
1
+ # Generated from lib/raptor/control_server.rb with RBS::Inline
2
+
3
+ module Raptor
4
+ # Serves cluster statistics over a Unix socket.
5
+ class ControlServer
6
+ MAX_REQUEST_SIZE: untyped
7
+
8
+ REQUEST_TIMEOUT: ::Integer
9
+
10
+ @running: AtomicBoolean
11
+
12
+ @thread: Thread?
13
+
14
+ @client: Atom
15
+
16
+ @server: UNIXServer?
17
+
18
+ @stats: ^() -> Hash[Symbol, untyped]
19
+
20
+ @path: String
21
+
22
+ # Creates a control server for `url` without binding it.
23
+ #
24
+ # @param url [String] `unix://` URL to listen on
25
+ # @yieldreturn [Hash] cluster statistics
26
+ # @return [void]
27
+ # @raise [ArgumentError] if the URL is not a Unix socket
28
+ #
29
+ # @rbs (String url) { () -> Hash[Symbol, untyped] } -> void
30
+ def initialize: (String url) { () -> Hash[Symbol, untyped] } -> void
31
+
32
+ # Binds the Unix socket.
33
+ #
34
+ # @return [void]
35
+ #
36
+ # @rbs () -> void
37
+ def bind: () -> void
38
+
39
+ # Starts serving requests in a background thread.
40
+ #
41
+ # @return [void]
42
+ #
43
+ # @rbs () -> void
44
+ def start: () -> void
45
+
46
+ # Stops serving and removes the socket.
47
+ #
48
+ # @return [void]
49
+ #
50
+ # @rbs () -> void
51
+ def shutdown: () -> void
52
+
53
+ private
54
+
55
+ # @rbs () -> void
56
+ def remove_stale_socket: () -> void
57
+
58
+ # @rbs () -> void
59
+ def serve: () -> void
60
+
61
+ # @rbs (UNIXSocket client) -> void
62
+ def handle: (UNIXSocket client) -> void
63
+
64
+ # @rbs (UNIXSocket client) -> String?
65
+ def read_request: (UNIXSocket client) -> String?
66
+
67
+ # @rbs () -> void
68
+ def close_client: () -> void
69
+ end
70
+ end
@@ -16,8 +16,6 @@ module Raptor
16
16
 
17
17
  RESPONSE_BUFFER_CAPACITY: untyped
18
18
 
19
- KEEPALIVE_READ_TIMEOUT: ::Float
20
-
21
19
  MAX_KEEPALIVE_REQUESTS: ::Integer
22
20
 
23
21
  HTTP_10: ::String
@@ -110,6 +108,10 @@ module Raptor
110
108
 
111
109
  @access_log_io: IO?
112
110
 
111
+ @clean_thread_locals: bool
112
+
113
+ @clean_fiber_locals: bool
114
+
113
115
  @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
114
116
 
115
117
  @running: AtomicBoolean
@@ -127,11 +129,13 @@ module Raptor
127
129
  # @param http1_options [Hash] HTTP/1.1-specific settings
128
130
  # @option http1_options [Integer] :max_keepalive_requests maximum requests per HTTP/1.1 keep-alive connection
129
131
  # @param access_log_io [IO, nil] IO to write Common Log Format access entries to, or nil to disable
132
+ # @param clean_thread_locals [Boolean] whether to clear application thread locals after each request
133
+ # @param clean_fiber_locals [Boolean] whether to process each request in a fresh Fiber
130
134
  # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
131
135
  # @return [void]
132
136
  #
133
- # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
134
- def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
137
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
138
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
135
139
 
136
140
  # Instance-level wrapper around {Http.parser_worker} that binds this
137
141
  # handler's env template and body-size limit into the worker proc.
@@ -289,6 +293,11 @@ module Raptor
289
293
  # @rbs (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
290
294
  def process_request: (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
291
295
 
296
+ # Calls the Rack app and writes its response for one request.
297
+ #
298
+ # @rbs (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
299
+ def perform_request: (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
300
+
292
301
  # Handles an exception raised while processing a request. Fires the
293
302
  # `rack.response_finished` callbacks with the error, writes a 500
294
303
  # response when no bytes have gone to the socket yet, and routes the
@@ -307,8 +316,9 @@ module Raptor
307
316
  def handle_app_error: (TCPSocket socket, Hash[String, untyped]? rack_env, Integer? status, Hash[String, String | Array[String]]? headers, Exception error, response_started: bool, hijacked: bool) -> void
308
317
 
309
318
  # Reads and processes subsequent requests inline on a kept-alive
310
- # connection. Falls back to the reactor when no data arrives within the
311
- # timeout, the thread pool is saturated, or the request is incomplete.
319
+ # connection. Returns the connection to the reactor when no data is ready
320
+ # or a request is incomplete, and queues complete requests behind work
321
+ # that is already waiting.
312
322
  #
313
323
  # @param socket [TCPSocket] the client socket
314
324
  # @param id [Integer] unique client identifier
@@ -152,6 +152,10 @@ module Raptor
152
152
 
153
153
  @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
154
154
 
155
+ @clean_fiber_locals: bool
156
+
157
+ @clean_thread_locals: bool
158
+
155
159
  @access_log_io: IO?
156
160
 
157
161
  @write_timeout: Integer
@@ -175,11 +179,13 @@ module Raptor
175
179
  # @param http2_options [Hash] HTTP/2-specific settings
176
180
  # @option http2_options [Integer] :max_concurrent_streams maximum HTTP/2 concurrent streams per connection
177
181
  # @param access_log_io [IO, nil] IO to write Common Log Format access entries to, or nil to disable
182
+ # @param clean_thread_locals [Boolean] whether to clear application thread locals after each request
183
+ # @param clean_fiber_locals [Boolean] whether to process each request in a fresh Fiber
178
184
  # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
179
185
  # @return [void]
180
186
  #
181
- # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
182
- def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
187
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
188
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
183
189
 
184
190
  # Creates a per-connection {Writer} configured with the handler's write timeout.
185
191
  #
@@ -304,6 +310,11 @@ module Raptor
304
310
  # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
305
311
  def dispatch_stream_request: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
306
312
 
313
+ # Calls the Rack app and writes its response for one stream.
314
+ #
315
+ # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
316
+ def perform_stream_request: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
317
+
307
318
  # Writes a Rack response as HTTP/2 frames to the socket, partitioning
308
319
  # DATA frames through `flow_control` to fit within the peer's windows.
309
320
  #
@@ -0,0 +1,24 @@
1
+ # Generated from lib/raptor/thread_locals.rb with RBS::Inline
2
+
3
+ module Raptor
4
+ # Owns Raptor's reusable per-thread values and clears application thread
5
+ # locals after each request.
6
+ module ThreadLocals
7
+ PRESERVED_KEYS: untyped
8
+
9
+ # Returns a reusable value stored on the current thread.
10
+ #
11
+ # @return [Object]
12
+ #
13
+ # @rbs (Symbol key) { () -> untyped } -> untyped
14
+ def self.fetch: (Symbol key) { () -> untyped } -> untyped
15
+
16
+ # Clears application-owned true thread locals while retaining Raptor's
17
+ # reusable per-thread values.
18
+ #
19
+ # @return [void]
20
+ #
21
+ # @rbs () -> void
22
+ def self.clear: () -> void
23
+ end
24
+ 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.19.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
@@ -157,6 +157,7 @@ files:
157
157
  - lib/raptor/binder.rb
158
158
  - lib/raptor/cli.rb
159
159
  - lib/raptor/cluster.rb
160
+ - lib/raptor/control_server.rb
160
161
  - lib/raptor/http.rb
161
162
  - lib/raptor/http1.rb
162
163
  - lib/raptor/http2.rb
@@ -166,12 +167,14 @@ files:
166
167
  - lib/raptor/server.rb
167
168
  - lib/raptor/stats.rb
168
169
  - lib/raptor/systemd.rb
170
+ - lib/raptor/thread_locals.rb
169
171
  - lib/raptor/version.rb
170
172
  - sig/generated/rackup/handler/raptor.rbs
171
173
  - sig/generated/raptor.rbs
172
174
  - sig/generated/raptor/binder.rbs
173
175
  - sig/generated/raptor/cli.rbs
174
176
  - sig/generated/raptor/cluster.rbs
177
+ - sig/generated/raptor/control_server.rbs
175
178
  - sig/generated/raptor/http.rbs
176
179
  - sig/generated/raptor/http1.rbs
177
180
  - sig/generated/raptor/http2.rbs
@@ -181,6 +184,7 @@ files:
181
184
  - sig/generated/raptor/server.rbs
182
185
  - sig/generated/raptor/stats.rbs
183
186
  - sig/generated/raptor/systemd.rbs
187
+ - sig/generated/raptor/thread_locals.rbs
184
188
  - sig/generated/raptor/version.rbs
185
189
  homepage: https://github.com/joshuay03/raptor
186
190
  licenses: