raptor 0.4.0 → 0.5.1
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/.mise.toml +2 -0
- data/Brewfile +2 -0
- data/CHANGELOG.md +12 -0
- data/README.md +27 -24
- data/ext/raptor_http/extconf.rb +1 -1
- data/ext/raptor_http2/extconf.rb +1 -1
- data/lib/rackup/handler/raptor.rb +18 -20
- data/lib/raptor/cli.rb +26 -10
- data/lib/raptor/cluster.rb +128 -56
- data/lib/raptor/http2.rb +4 -3
- data/lib/raptor/log.rb +55 -0
- data/lib/raptor/reactor.rb +25 -29
- data/lib/raptor/request.rb +10 -16
- data/lib/raptor/server.rb +17 -19
- data/lib/raptor/stats.rb +30 -26
- data/lib/raptor/version.rb +1 -1
- data/sig/generated/raptor/cli.rbs +1 -1
- data/sig/generated/raptor/cluster.rbs +69 -37
- data/sig/generated/raptor/http2.rbs +2 -1
- data/sig/generated/raptor/log.rbs +41 -0
- data/sig/generated/raptor/reactor.rbs +23 -26
- data/sig/generated/raptor/request.rbs +6 -13
- data/sig/generated/raptor/server.rbs +14 -16
- data/sig/generated/raptor/stats.rbs +24 -20
- metadata +5 -1
data/lib/raptor/http2.rb
CHANGED
|
@@ -81,7 +81,8 @@ module Raptor
|
|
|
81
81
|
# outbound DATA frames respect RFC 7540 §5.2. Threads dispatching stream
|
|
82
82
|
# responses call `acquire` to reserve send capacity; threads applying
|
|
83
83
|
# inbound WINDOW_UPDATE or SETTINGS frames call the mutating methods to
|
|
84
|
-
# replenish it.
|
|
84
|
+
# replenish it. The connection window and per-stream windows live in
|
|
85
|
+
# separate `Atom`s so the common fast path skips per-stream tracking.
|
|
85
86
|
#
|
|
86
87
|
class FlowControl
|
|
87
88
|
ACQUIRE_POLL_INTERVAL = 0.001
|
|
@@ -529,7 +530,7 @@ module Raptor
|
|
|
529
530
|
|
|
530
531
|
result[:completed_requests]&.each do |request|
|
|
531
532
|
stream_id = request[:stream_id]
|
|
532
|
-
remote_addr = result[:remote_addr] ||
|
|
533
|
+
remote_addr = result[:remote_addr] || Server::DEFAULT_REMOTE_ADDR
|
|
533
534
|
|
|
534
535
|
thread_pool << proc do
|
|
535
536
|
dispatch_stream_request(
|
|
@@ -749,7 +750,7 @@ module Raptor
|
|
|
749
750
|
env[Rack::SERVER_NAME] ||= host
|
|
750
751
|
env[Rack::SERVER_PORT] ||= port || @server_port.to_s
|
|
751
752
|
else
|
|
752
|
-
env[Rack::SERVER_NAME] ||=
|
|
753
|
+
env[Rack::SERVER_NAME] ||= Server::DEFAULT_SERVER_NAME
|
|
753
754
|
env[Rack::SERVER_PORT] ||= @server_port.to_s
|
|
754
755
|
end
|
|
755
756
|
end
|
data/lib/raptor/log.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Raptor
|
|
5
|
+
# Shared logging helpers. Every line is prefixed with
|
|
6
|
+
# `[Raptor <pid>|<ractor>|<thread>]` so output is identifiable
|
|
7
|
+
# and traceable to its source in a mixed log stream.
|
|
8
|
+
#
|
|
9
|
+
module Log
|
|
10
|
+
# Writes an informational message to stdout.
|
|
11
|
+
#
|
|
12
|
+
# @param message [String] the message to log
|
|
13
|
+
# @return [void]
|
|
14
|
+
#
|
|
15
|
+
# @rbs (String message) -> void
|
|
16
|
+
def self.info(message)
|
|
17
|
+
Kernel.puts "#{prefix} #{message}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Writes a warning to stderr.
|
|
21
|
+
#
|
|
22
|
+
# @param message [String] the message to log
|
|
23
|
+
# @return [void]
|
|
24
|
+
#
|
|
25
|
+
# @rbs (String message) -> void
|
|
26
|
+
def self.warn(message)
|
|
27
|
+
Kernel.warn "#{prefix} #{message}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Logs a rescued exception to stderr. The full message (class,
|
|
31
|
+
# message, backtrace) is written on subsequent unprefixed lines.
|
|
32
|
+
#
|
|
33
|
+
# @param error [Exception] the rescued exception
|
|
34
|
+
# @return [void]
|
|
35
|
+
#
|
|
36
|
+
# @rbs (Exception error) -> void
|
|
37
|
+
def self.rescued_error(error)
|
|
38
|
+
Kernel.warn "#{prefix} rescued:"
|
|
39
|
+
Kernel.warn error.full_message
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Builds the log line prefix from the current process, ractor,
|
|
43
|
+
# and thread. Unnamed ractors and threads are reported as `main`.
|
|
44
|
+
#
|
|
45
|
+
# @return [String] the prefix
|
|
46
|
+
#
|
|
47
|
+
# @rbs () -> String
|
|
48
|
+
def self.prefix
|
|
49
|
+
ractor = Ractor.current.name || "main"
|
|
50
|
+
thread = Thread.current.name || "main"
|
|
51
|
+
"[Raptor #{Process.pid}|#{ractor}|#{thread}]"
|
|
52
|
+
end
|
|
53
|
+
private_class_method :prefix
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/raptor/reactor.rb
CHANGED
|
@@ -9,12 +9,12 @@ module Raptor
|
|
|
9
9
|
#
|
|
10
10
|
# Reactor uses NIO selectors for efficient I/O multiplexing and implements
|
|
11
11
|
# client timeouts using a red-black tree for O(log n) timeout management.
|
|
12
|
-
# It coordinates between
|
|
13
|
-
# pools for
|
|
14
|
-
#
|
|
12
|
+
# It coordinates between ractor pools for CPU-intensive HTTP parsing and
|
|
13
|
+
# thread pools for blocking operations, and provides backlog metrics that
|
|
14
|
+
# the server uses for backpressure control to prevent overload.
|
|
15
15
|
#
|
|
16
16
|
# @example
|
|
17
|
-
# reactor = Reactor.new(
|
|
17
|
+
# reactor = Reactor.new(ractor_pool, thread_pool, client_options: {
|
|
18
18
|
# first_data_timeout: 30,
|
|
19
19
|
# chunk_data_timeout: 10
|
|
20
20
|
# })
|
|
@@ -24,38 +24,38 @@ module Raptor
|
|
|
24
24
|
# reactor.shutdown
|
|
25
25
|
#
|
|
26
26
|
class Reactor
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# TimeoutClient extends RedBlackTree::Node to enable efficient timeout
|
|
30
|
-
# management using the tree's ordering properties.
|
|
27
|
+
# A client connection node ordered by absolute expiry time so the
|
|
28
|
+
# soonest-to-expire is always at the tree's minimum.
|
|
31
29
|
#
|
|
32
30
|
class TimeoutClient < RedBlackTree::Node
|
|
33
31
|
# @rbs attr_accessor timeout_at: Float
|
|
34
32
|
attr_accessor :timeout_at
|
|
35
33
|
|
|
36
|
-
#
|
|
34
|
+
# Semantic alias for the inherited `data` slot.
|
|
37
35
|
#
|
|
38
|
-
# @return [Hash] the client connection state
|
|
36
|
+
# @return [Hash] the client connection state
|
|
39
37
|
#
|
|
40
38
|
# @rbs () -> Hash[Symbol, untyped]
|
|
41
39
|
def client_data
|
|
42
40
|
data
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
#
|
|
43
|
+
# Returns seconds until expiry, clamped to 0 so an already-expired
|
|
44
|
+
# client doesn't push the next selector wait into the future.
|
|
46
45
|
#
|
|
47
46
|
# @param now [Float] current monotonic timestamp
|
|
48
|
-
# @return [Float]
|
|
47
|
+
# @return [Float] seconds until expiry, never negative
|
|
49
48
|
#
|
|
50
49
|
# @rbs (Float now) -> Float
|
|
51
50
|
def timeout(now)
|
|
52
51
|
[timeout_at - now, 0].max
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
#
|
|
54
|
+
# Orders nodes by `timeout_at` so the tree minimum is the next
|
|
55
|
+
# client to expire.
|
|
56
56
|
#
|
|
57
57
|
# @param other [TimeoutClient] another timeout client to compare
|
|
58
|
-
# @return [Integer] -1, 0, or 1
|
|
58
|
+
# @return [Integer] -1, 0, or 1
|
|
59
59
|
#
|
|
60
60
|
# @rbs (TimeoutClient other) -> Integer
|
|
61
61
|
def <=>(other)
|
|
@@ -80,18 +80,18 @@ module Raptor
|
|
|
80
80
|
|
|
81
81
|
# Creates a new Reactor instance.
|
|
82
82
|
#
|
|
83
|
-
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
84
83
|
# @param ractor_pool [RactorPool] ractor pool for HTTP parsing
|
|
84
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
85
85
|
# @param client_options [Hash] timeout configuration options
|
|
86
86
|
# @option client_options [Integer] :first_data_timeout timeout for initial data
|
|
87
87
|
# @option client_options [Integer] :chunk_data_timeout timeout for subsequent chunks
|
|
88
88
|
# @option client_options [Integer] :persistent_data_timeout timeout for keep-alive connections
|
|
89
89
|
# @return [void]
|
|
90
90
|
#
|
|
91
|
-
# @rbs (untyped
|
|
92
|
-
def initialize(
|
|
93
|
-
@thread_pool = thread_pool
|
|
91
|
+
# @rbs (untyped ractor_pool, untyped thread_pool, client_options: Hash[Symbol, Integer]) -> void
|
|
92
|
+
def initialize(ractor_pool, thread_pool, client_options:)
|
|
94
93
|
@ractor_pool = ractor_pool
|
|
94
|
+
@thread_pool = thread_pool
|
|
95
95
|
@client_options = client_options
|
|
96
96
|
|
|
97
97
|
@selector = NIO::Selector.new
|
|
@@ -149,8 +149,7 @@ module Raptor
|
|
|
149
149
|
register(@queue.pop)
|
|
150
150
|
end
|
|
151
151
|
rescue => error
|
|
152
|
-
|
|
153
|
-
warn error.full_message
|
|
152
|
+
Log.rescued_error(error)
|
|
154
153
|
end
|
|
155
154
|
end
|
|
156
155
|
|
|
@@ -200,13 +199,12 @@ module Raptor
|
|
|
200
199
|
socket.close
|
|
201
200
|
end
|
|
202
201
|
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
#
|
|
206
|
-
# processing. Triggers server accept re-enabling if system capacity allows.
|
|
202
|
+
# Drops the reactor's references to a client whose parsed request
|
|
203
|
+
# has been handed off to the thread pool. The socket itself is kept
|
|
204
|
+
# open so the worker can write the response.
|
|
207
205
|
#
|
|
208
206
|
# @param id [Integer] unique client identifier
|
|
209
|
-
# @return [TCPSocket, nil] the
|
|
207
|
+
# @return [TCPSocket, nil] the socket associated with `id`, if any
|
|
210
208
|
#
|
|
211
209
|
# @rbs (Integer id) -> TCPSocket?
|
|
212
210
|
def remove(id)
|
|
@@ -321,10 +319,8 @@ module Raptor
|
|
|
321
319
|
socket.close rescue nil
|
|
322
320
|
end
|
|
323
321
|
|
|
324
|
-
#
|
|
325
|
-
#
|
|
326
|
-
# Closes the registration queue and wakes up the selector to begin
|
|
327
|
-
# graceful shutdown process.
|
|
322
|
+
# Closes the registration queue and wakes the selector so the
|
|
323
|
+
# event loop drains pending work and exits.
|
|
328
324
|
#
|
|
329
325
|
# @return [void]
|
|
330
326
|
#
|
data/lib/raptor/request.rb
CHANGED
|
@@ -11,13 +11,10 @@ require "rack"
|
|
|
11
11
|
require_relative "raptor_http"
|
|
12
12
|
|
|
13
13
|
module Raptor
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# low-level HTTP parsing and high-level Rack application interface, handling
|
|
19
|
-
# both incomplete requests (that need more data) and complete requests
|
|
20
|
-
# (ready for application processing).
|
|
14
|
+
# Parses HTTP/1.x requests and dispatches them to the Rack
|
|
15
|
+
# application. Coordinates with the Ractor pool for parsing and
|
|
16
|
+
# with the reactor for requests that need more data before they
|
|
17
|
+
# can be handled.
|
|
21
18
|
#
|
|
22
19
|
class Request
|
|
23
20
|
BODY_BUFFER_THRESHOLD = 256 * 1024
|
|
@@ -27,7 +24,6 @@ module Raptor
|
|
|
27
24
|
KEEPALIVE_READ_TIMEOUT = 0.001
|
|
28
25
|
MAX_KEEPALIVE_REQUESTS = 100
|
|
29
26
|
|
|
30
|
-
HTTP_SCHEME = "http"
|
|
31
27
|
HTTP_10 = "HTTP/1.0"
|
|
32
28
|
HTTP_11 = "HTTP/1.1"
|
|
33
29
|
STATUS_LINE_CACHE_10 = Hash.new do |h, status|
|
|
@@ -94,10 +90,8 @@ module Raptor
|
|
|
94
90
|
[decoded, :incomplete]
|
|
95
91
|
end
|
|
96
92
|
|
|
97
|
-
# Writes
|
|
98
|
-
#
|
|
99
|
-
# Uses write_nonblock with `WRITE_TIMEOUT` to avoid blocking the thread
|
|
100
|
-
# indefinitely on slow clients.
|
|
93
|
+
# Writes `string` in full, retrying on partial writes. Bounded by
|
|
94
|
+
# `WRITE_TIMEOUT` so a slow client can't pin the writing thread.
|
|
101
95
|
#
|
|
102
96
|
# @param socket [TCPSocket] the socket to write to
|
|
103
97
|
# @param string [String] the data to write
|
|
@@ -330,8 +324,8 @@ module Raptor
|
|
|
330
324
|
else
|
|
331
325
|
socket = reactor.remove(parsed_request[:id])
|
|
332
326
|
request_count = (parsed_request[:request_count] || 0) + 1
|
|
333
|
-
remote_addr = parsed_request[:remote_addr] ||
|
|
334
|
-
url_scheme = parsed_request[:url_scheme] || HTTP_SCHEME
|
|
327
|
+
remote_addr = parsed_request[:remote_addr] || Server::DEFAULT_REMOTE_ADDR
|
|
328
|
+
url_scheme = parsed_request[:url_scheme] || Server::HTTP_SCHEME
|
|
335
329
|
|
|
336
330
|
thread_pool << proc do
|
|
337
331
|
process_client(
|
|
@@ -607,7 +601,7 @@ module Raptor
|
|
|
607
601
|
# @return [Hash] fully populated Rack environment hash
|
|
608
602
|
#
|
|
609
603
|
# @rbs (Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, TCPSocket socket, ?remote_addr: String, ?url_scheme: String) -> Hash[String, untyped]
|
|
610
|
-
def build_rack_env(env, parse_data, body, socket, remote_addr:
|
|
604
|
+
def build_rack_env(env, parse_data, body, socket, remote_addr: Server::DEFAULT_REMOTE_ADDR, url_scheme: Server::HTTP_SCHEME)
|
|
611
605
|
env[Rack::RACK_VERSION] = Rack::VERSION
|
|
612
606
|
env[Rack::RACK_URL_SCHEME] = url_scheme
|
|
613
607
|
env[Rack::RACK_INPUT] = build_rack_input(body)
|
|
@@ -647,7 +641,7 @@ module Raptor
|
|
|
647
641
|
env[Rack::SERVER_NAME] ||= host
|
|
648
642
|
env[Rack::SERVER_PORT] ||= port || @server_port.to_s
|
|
649
643
|
else
|
|
650
|
-
env[Rack::SERVER_NAME] ||=
|
|
644
|
+
env[Rack::SERVER_NAME] ||= Server::DEFAULT_SERVER_NAME
|
|
651
645
|
env[Rack::SERVER_PORT] ||= @server_port.to_s
|
|
652
646
|
end
|
|
653
647
|
|
data/lib/raptor/server.rb
CHANGED
|
@@ -6,26 +6,20 @@ require "socket"
|
|
|
6
6
|
require "atomic-ruby/atomic_boolean"
|
|
7
7
|
|
|
8
8
|
module Raptor
|
|
9
|
-
#
|
|
9
|
+
# Accepts client connections and dispatches them into the request
|
|
10
|
+
# pipeline. Skips acceptance when the reactor backlog is high so an
|
|
11
|
+
# overloaded process leaves connections for peers that can absorb
|
|
12
|
+
# them (via shared `SO_REUSEPORT` listeners).
|
|
10
13
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is
|
|
17
|
-
# applied only to TCP sockets, and SSL handshakes are offloaded to the thread
|
|
18
|
-
# pool so a slow client cannot block the server thread.
|
|
19
|
-
#
|
|
20
|
-
# For HTTP/1.1 connections the first request is parsed inline on the server
|
|
21
|
-
# thread and dispatched directly to the thread pool, falling back to the
|
|
22
|
-
# reactor only when more data is needed. For HTTP/2 connections (negotiated
|
|
23
|
-
# via ALPN) the server sends initial SETTINGS and registers the connection
|
|
24
|
-
# with the reactor for frame processing through the ractor pool.
|
|
14
|
+
# Supports TCP, Unix, and SSL listeners. SSL handshakes are offloaded
|
|
15
|
+
# to the thread pool so a slow client can't pin the server thread.
|
|
16
|
+
# For HTTP/1.1 the first request is parsed inline and dispatched
|
|
17
|
+
# straight to the thread pool; HTTP/2 (negotiated via ALPN) is
|
|
18
|
+
# registered with the reactor for frame processing.
|
|
25
19
|
#
|
|
26
20
|
# @example
|
|
27
21
|
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
28
|
-
# reactor = Reactor.new(
|
|
22
|
+
# reactor = Reactor.new(ractor_pool, thread_pool, client_options: {})
|
|
29
23
|
# request = Request.new(app, 3000)
|
|
30
24
|
# server = Server.new(binder, reactor, thread_pool, request, client_options: { first_data_timeout: 30 })
|
|
31
25
|
# server.run
|
|
@@ -35,8 +29,12 @@ module Raptor
|
|
|
35
29
|
class Server
|
|
36
30
|
HTTP_SCHEME = "http"
|
|
37
31
|
HTTPS_SCHEME = "https"
|
|
32
|
+
|
|
38
33
|
H2_PROTOCOL = "h2"
|
|
39
34
|
|
|
35
|
+
DEFAULT_REMOTE_ADDR = "127.0.0.1"
|
|
36
|
+
DEFAULT_SERVER_NAME = "localhost"
|
|
37
|
+
|
|
40
38
|
# @rbs @binder: Binder
|
|
41
39
|
# @rbs @reactor: Reactor
|
|
42
40
|
# @rbs @thread_pool: AtomicThreadPool
|
|
@@ -133,7 +131,7 @@ module Raptor
|
|
|
133
131
|
tcp_client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
134
132
|
remote_addr = tcp_client.remote_address.ip_address
|
|
135
133
|
else
|
|
136
|
-
remote_addr =
|
|
134
|
+
remote_addr = DEFAULT_REMOTE_ADDR
|
|
137
135
|
end
|
|
138
136
|
|
|
139
137
|
if listener.is_a?(Binder::SslListener)
|
|
@@ -218,7 +216,7 @@ module Raptor
|
|
|
218
216
|
|
|
219
217
|
retry
|
|
220
218
|
rescue OpenSSL::SSL::SSLError => error
|
|
221
|
-
|
|
219
|
+
Log.rescued_error(error)
|
|
222
220
|
ssl_socket.close rescue nil
|
|
223
221
|
false
|
|
224
222
|
end
|
|
@@ -244,7 +242,7 @@ module Raptor
|
|
|
244
242
|
end
|
|
245
243
|
return true if ready
|
|
246
244
|
|
|
247
|
-
warn "SSL handshake timed out"
|
|
245
|
+
Log.warn "SSL handshake timed out"
|
|
248
246
|
ssl_socket.close rescue nil
|
|
249
247
|
false
|
|
250
248
|
end
|
data/lib/raptor/stats.rb
CHANGED
|
@@ -12,26 +12,27 @@ module Raptor
|
|
|
12
12
|
# assigned a fixed-size slot in the shared region.
|
|
13
13
|
#
|
|
14
14
|
# Binary layout per slot (native byte order):
|
|
15
|
-
# pid
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
15
|
+
# pid uint32 4 bytes
|
|
16
|
+
# index uint32 4 bytes
|
|
17
|
+
# phase uint32 4 bytes
|
|
18
|
+
# requests uint64 8 bytes
|
|
19
|
+
# backlog uint32 4 bytes
|
|
20
|
+
# busy_threads uint32 4 bytes
|
|
21
|
+
# thread_capacity uint32 4 bytes
|
|
22
|
+
# started_at float64 8 bytes
|
|
23
|
+
# last_checkin float64 8 bytes
|
|
24
|
+
# booted uint8 1 byte
|
|
25
|
+
# 49 bytes total
|
|
22
26
|
#
|
|
23
27
|
class Stats
|
|
24
|
-
SLOT_FORMAT = "
|
|
25
|
-
SLOT_SIZE = [0, 0, 0, 0.0, 0.0, 0].pack(SLOT_FORMAT).bytesize
|
|
28
|
+
SLOT_FORMAT = "LLLQLLLddC"
|
|
29
|
+
SLOT_SIZE = [0, 0, 0, 0, 0, 0, 0, 0.0, 0.0, 0].pack(SLOT_FORMAT).bytesize
|
|
26
30
|
|
|
27
31
|
# @rbs @num_workers: Integer
|
|
28
32
|
# @rbs @mmap: untyped
|
|
29
33
|
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# Allocates a MAP_ANON | MAP_SHARED mmap region large enough for
|
|
33
|
-
# num_workers slots. Must be called before forking so that all
|
|
34
|
-
# worker processes share the same backing memory.
|
|
34
|
+
# Allocates the shared mmap region. Must be called before forking
|
|
35
|
+
# workers so the mapping is inherited by every child process.
|
|
35
36
|
#
|
|
36
37
|
# @param num_workers [Integer] number of worker slots to allocate
|
|
37
38
|
# @return [void]
|
|
@@ -44,24 +45,27 @@ module Raptor
|
|
|
44
45
|
|
|
45
46
|
# Writes stats for a worker slot into shared memory.
|
|
46
47
|
#
|
|
47
|
-
# @param index [Integer] slot index to write into
|
|
48
|
+
# @param index [Integer] slot index to write into; also written into the slot itself
|
|
48
49
|
# @param pid [Integer] worker process ID
|
|
50
|
+
# @param phase [Integer] cluster phase this worker was forked at
|
|
49
51
|
# @param requests [Integer] total requests handled by this worker
|
|
50
52
|
# @param backlog [Integer] current queue depth
|
|
53
|
+
# @param busy_threads [Integer] worker threads currently processing requests
|
|
54
|
+
# @param thread_capacity [Integer] worker threads configured for this worker
|
|
51
55
|
# @param started_at [Float] process start time as a Unix timestamp
|
|
52
56
|
# @param last_checkin [Float] time of last stats write as a Unix timestamp
|
|
53
57
|
# @param booted [Boolean] whether the worker has finished starting
|
|
54
58
|
# @return [void]
|
|
55
59
|
#
|
|
56
|
-
# @rbs (Integer index, pid: Integer, requests: Integer, backlog: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
57
|
-
def write(index, pid:, requests:, backlog:, started_at:, last_checkin:, booted:)
|
|
58
|
-
data = [pid, requests, backlog, started_at, last_checkin, booted ? 1 : 0].pack(SLOT_FORMAT)
|
|
60
|
+
# @rbs (Integer index, pid: Integer, phase: Integer, requests: Integer, backlog: Integer, busy_threads: Integer, thread_capacity: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
61
|
+
def write(index, pid:, phase:, requests:, backlog:, busy_threads:, thread_capacity:, started_at:, last_checkin:, booted:)
|
|
62
|
+
data = [pid, index, phase, requests, backlog, busy_threads, thread_capacity, started_at, last_checkin, booted ? 1 : 0].pack(SLOT_FORMAT)
|
|
59
63
|
@mmap.semlock { @mmap[index * SLOT_SIZE, SLOT_SIZE] = data }
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
# Returns stats for all worker slots.
|
|
63
67
|
#
|
|
64
|
-
# @return [Array<Hash>] per-worker stat hashes with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
68
|
+
# @return [Array<Hash>] per-worker stat hashes with :pid, :index, :phase, :requests, :backlog, :busy_threads, :thread_capacity, :started_at, :last_checkin, and :booted
|
|
65
69
|
#
|
|
66
70
|
# @rbs () -> Array[Hash[Symbol, untyped]]
|
|
67
71
|
def all
|
|
@@ -81,14 +85,14 @@ module Raptor
|
|
|
81
85
|
|
|
82
86
|
# Reads stats for a worker slot from shared memory.
|
|
83
87
|
#
|
|
84
|
-
# @param
|
|
85
|
-
# @return [Hash] stat hash with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
88
|
+
# @param slot [Integer] slot offset to read from
|
|
89
|
+
# @return [Hash] stat hash with :pid, :index, :phase, :requests, :backlog, :busy_threads, :thread_capacity, :started_at, :last_checkin, and :booted
|
|
86
90
|
#
|
|
87
|
-
# @rbs (Integer
|
|
88
|
-
def read(
|
|
89
|
-
data = @mmap[
|
|
90
|
-
pid, requests, backlog, started_at, last_checkin, booted = data.unpack(SLOT_FORMAT)
|
|
91
|
-
{ pid:, requests:, backlog:, started_at:, last_checkin:, booted: booted == 1 }
|
|
91
|
+
# @rbs (Integer slot) -> Hash[Symbol, untyped]
|
|
92
|
+
def read(slot)
|
|
93
|
+
data = @mmap[slot * SLOT_SIZE, SLOT_SIZE]
|
|
94
|
+
pid, index, phase, requests, backlog, busy_threads, thread_capacity, started_at, last_checkin, booted = data.unpack(SLOT_FORMAT)
|
|
95
|
+
{ pid:, index:, phase:, requests:, backlog:, busy_threads:, thread_capacity:, started_at:, last_checkin:, booted: booted == 1 }
|
|
92
96
|
end
|
|
93
97
|
end
|
|
94
98
|
end
|
data/lib/raptor/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Raptor
|
|
|
5
5
|
#
|
|
6
6
|
# CLI parses command-line arguments and starts the server cluster with the
|
|
7
7
|
# specified configuration options. It supports configuring the number of
|
|
8
|
-
# workers,
|
|
8
|
+
# workers, ractors, threads, bind addresses, and various client timeout
|
|
9
9
|
# settings.
|
|
10
10
|
#
|
|
11
11
|
# @example Basic usage
|