raptor 0.7.0 → 0.9.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 +90 -32
- data/.dockerignore +5 -0
- data/CHANGELOG.md +30 -0
- data/Dockerfile +28 -0
- data/README.md +159 -27
- data/Rakefile +19 -1
- data/docs/raptor-vs-puma.md +557 -0
- data/ext/raptor_bpf/reuseport_select.bpf.c +63 -0
- data/ext/raptor_http/extconf.rb +1 -1
- data/ext/raptor_native/extconf.rb +7 -0
- data/ext/raptor_native/raptor_native.c +99 -0
- data/lib/rackup/handler/raptor.rb +12 -2
- data/lib/raptor/binder.rb +139 -31
- data/lib/raptor/cli.rb +83 -22
- data/lib/raptor/cluster.rb +214 -33
- data/lib/raptor/http.rb +116 -0
- data/lib/raptor/{request.rb → http1.rb} +228 -99
- data/lib/raptor/http2.rb +85 -40
- data/lib/raptor/reactor.rb +22 -15
- data/lib/raptor/reuseport_bpf.rb +108 -0
- data/lib/raptor/server.rb +92 -43
- data/lib/raptor/stats.rb +1 -1
- data/lib/raptor/systemd.rb +69 -0
- data/lib/raptor/version.rb +1 -1
- data/sig/generated/raptor/binder.rbs +82 -5
- data/sig/generated/raptor/cli.rbs +2 -3
- data/sig/generated/raptor/cluster.rbs +91 -13
- data/sig/generated/raptor/http.rbs +65 -0
- data/sig/generated/raptor/{request.rbs → http1.rbs} +122 -35
- data/sig/generated/raptor/http2.rbs +46 -13
- data/sig/generated/raptor/reactor.rbs +18 -11
- data/sig/generated/raptor/reuseport_bpf.rbs +56 -0
- data/sig/generated/raptor/server.rbs +49 -21
- data/sig/generated/raptor/systemd.rbs +42 -0
- metadata +30 -3
|
@@ -10,10 +10,12 @@ module Raptor
|
|
|
10
10
|
# the server uses for backpressure control to prevent overload.
|
|
11
11
|
#
|
|
12
12
|
# @example
|
|
13
|
-
# reactor = Reactor.new(
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
13
|
+
# reactor = Reactor.new(
|
|
14
|
+
# ractor_pool,
|
|
15
|
+
# thread_pool,
|
|
16
|
+
# connection_options: { first_data_timeout: 30, chunk_data_timeout: 10 },
|
|
17
|
+
# http1_options: { persistent_data_timeout: 65 }
|
|
18
|
+
# )
|
|
17
19
|
# reactor.run
|
|
18
20
|
# reactor.add(id: client.object_id, socket: client)
|
|
19
21
|
# # ... later
|
|
@@ -71,7 +73,11 @@ module Raptor
|
|
|
71
73
|
|
|
72
74
|
@selector: NIO::Selector
|
|
73
75
|
|
|
74
|
-
@
|
|
76
|
+
@persistent_data_timeout: Integer
|
|
77
|
+
|
|
78
|
+
@chunk_data_timeout: Integer
|
|
79
|
+
|
|
80
|
+
@first_data_timeout: Integer
|
|
75
81
|
|
|
76
82
|
@ractor_pool: untyped
|
|
77
83
|
|
|
@@ -81,14 +87,15 @@ module Raptor
|
|
|
81
87
|
#
|
|
82
88
|
# @param ractor_pool [RactorPool] ractor pool for HTTP parsing
|
|
83
89
|
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
84
|
-
# @param
|
|
85
|
-
# @option
|
|
86
|
-
# @option
|
|
87
|
-
# @
|
|
90
|
+
# @param connection_options [Hash] per-connection timeout configuration
|
|
91
|
+
# @option connection_options [Integer] :first_data_timeout timeout for initial data
|
|
92
|
+
# @option connection_options [Integer] :chunk_data_timeout timeout for subsequent chunks
|
|
93
|
+
# @param http1_options [Hash] HTTP/1.1-specific configuration
|
|
94
|
+
# @option http1_options [Integer] :persistent_data_timeout timeout for keep-alive idle connections
|
|
88
95
|
# @return [void]
|
|
89
96
|
#
|
|
90
|
-
# @rbs (untyped ractor_pool, untyped thread_pool,
|
|
91
|
-
def initialize: (untyped ractor_pool, untyped thread_pool,
|
|
97
|
+
# @rbs (untyped ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped]) -> void
|
|
98
|
+
def initialize: (untyped ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped]) -> void
|
|
92
99
|
|
|
93
100
|
# Starts the reactor's main event loop in a new thread.
|
|
94
101
|
#
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Generated from lib/raptor/reuseport_bpf.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Routes incoming connections across worker processes to the worker with
|
|
5
|
+
# the lowest reactor backlog.
|
|
6
|
+
#
|
|
7
|
+
# Auto-enabled on Linux when the `libbpf-ruby` gem is installed and the
|
|
8
|
+
# BPF object file has been compiled. Falls back silently to standard
|
|
9
|
+
# `SO_REUSEPORT` when either is missing. Raises when the kernel refuses
|
|
10
|
+
# the BPF program. Wraps `tcp://` bindings only; non-tcp bindings are
|
|
11
|
+
# left to the binder's shared listeners.
|
|
12
|
+
module ReuseportBPF
|
|
13
|
+
LIBBPF_LOADED: untyped
|
|
14
|
+
|
|
15
|
+
BPF_OBJECT_PATH: untyped
|
|
16
|
+
|
|
17
|
+
# Whether the preconditions for BPF-directed reuseport are met on this
|
|
18
|
+
# platform. Does not imply that the kernel will accept the program.
|
|
19
|
+
#
|
|
20
|
+
# @return [Boolean]
|
|
21
|
+
#
|
|
22
|
+
# @rbs () -> bool
|
|
23
|
+
def self.supported?: () -> bool
|
|
24
|
+
|
|
25
|
+
# Prepares BPF-directed routing for `worker_count` workers.
|
|
26
|
+
#
|
|
27
|
+
# Returns true when BPF-directed dispatch is active. Returns false
|
|
28
|
+
# when the platform is unsupported. Raises when the kernel refuses
|
|
29
|
+
# the program.
|
|
30
|
+
#
|
|
31
|
+
# @param worker_count [Integer] number of worker processes that will bind sockets
|
|
32
|
+
# @return [Boolean]
|
|
33
|
+
#
|
|
34
|
+
# @rbs (Integer worker_count) -> bool
|
|
35
|
+
def self.setup: (Integer worker_count) -> bool
|
|
36
|
+
|
|
37
|
+
# Returns tcp listening sockets bound and registered for `worker_index`.
|
|
38
|
+
# Skips non-tcp bind URIs.
|
|
39
|
+
#
|
|
40
|
+
# @param bind_uris [Array<String>] the configured bind URIs
|
|
41
|
+
# @param worker_index [Integer] slot index for this worker in the socks map
|
|
42
|
+
# @param socket_backlog [Integer] kernel listen() queue depth
|
|
43
|
+
# @return [Array<TCPServer>] the tcp listening sockets created for this worker
|
|
44
|
+
#
|
|
45
|
+
# @rbs (Array[String] bind_uris, Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
|
|
46
|
+
def self.create_worker_listeners: (Array[String] bind_uris, Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
|
|
47
|
+
|
|
48
|
+
# Publishes this worker's current backlog to the BPF map.
|
|
49
|
+
#
|
|
50
|
+
# @param backlog [Integer] the worker's current reactor backlog
|
|
51
|
+
# @return [void]
|
|
52
|
+
#
|
|
53
|
+
# @rbs (Integer backlog) -> void
|
|
54
|
+
def self.update_load: (Integer backlog) -> void
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -14,9 +14,10 @@ module Raptor
|
|
|
14
14
|
#
|
|
15
15
|
# @example
|
|
16
16
|
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
17
|
-
# reactor = Reactor.new(ractor_pool, thread_pool,
|
|
18
|
-
#
|
|
19
|
-
#
|
|
17
|
+
# reactor = Reactor.new(ractor_pool, thread_pool, connection_options: {}, http1_options: {})
|
|
18
|
+
# http1 = Http1.new(app, 3000)
|
|
19
|
+
# http2 = Http2.new(app, 3000)
|
|
20
|
+
# server = Server.new(binder, reactor, thread_pool, http1, http2, connection_options: { first_data_timeout: 30 }, listeners: binder.listeners)
|
|
20
21
|
# server.run
|
|
21
22
|
# # ... later
|
|
22
23
|
# server.shutdown
|
|
@@ -35,14 +36,22 @@ module Raptor
|
|
|
35
36
|
|
|
36
37
|
@running: AtomicBoolean
|
|
37
38
|
|
|
38
|
-
@
|
|
39
|
+
@bpf_active: bool
|
|
39
40
|
|
|
40
|
-
@
|
|
41
|
+
@drain_accept_queue: bool
|
|
42
|
+
|
|
43
|
+
@first_data_timeout: Integer
|
|
44
|
+
|
|
45
|
+
@http2: Http2
|
|
46
|
+
|
|
47
|
+
@http1: Http1
|
|
41
48
|
|
|
42
49
|
@thread_pool: AtomicThreadPool
|
|
43
50
|
|
|
44
51
|
@reactor: Reactor
|
|
45
52
|
|
|
53
|
+
@listeners: Array[TCPServer | UNIXServer | Binder::SslListener]
|
|
54
|
+
|
|
46
55
|
@binder: Binder
|
|
47
56
|
|
|
48
57
|
# Creates a new Server instance.
|
|
@@ -50,19 +59,23 @@ module Raptor
|
|
|
50
59
|
# @param binder [Binder] the binder managing listening sockets
|
|
51
60
|
# @param reactor [Reactor] the reactor for handling client connections
|
|
52
61
|
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
53
|
-
# @param
|
|
54
|
-
# @param
|
|
62
|
+
# @param http1 [Http1] the HTTP/1.1 handler
|
|
63
|
+
# @param http2 [Http2] the HTTP/2 handler (provides the initial SETTINGS frame)
|
|
64
|
+
# @param connection_options [Hash] per-connection timeout configuration, used to bound TLS handshakes
|
|
65
|
+
# @param listeners [Array] the per-worker listeners this server accepts on
|
|
66
|
+
# @param drain_accept_queue [Boolean] whether to drain the kernel accept queue on shutdown
|
|
67
|
+
# @param worker_index [Integer, nil] the slot index for BPF load reporting
|
|
55
68
|
# @return [void]
|
|
56
69
|
#
|
|
57
|
-
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool,
|
|
58
|
-
def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool,
|
|
70
|
+
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Http1 http1, Http2 http2, connection_options: Hash[Symbol, untyped], listeners: Array[untyped], ?drain_accept_queue: bool, ?worker_index: Integer?) -> void
|
|
71
|
+
def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Http1 http1, Http2 http2, connection_options: Hash[Symbol, untyped], listeners: Array[untyped], ?drain_accept_queue: bool, ?worker_index: Integer?) -> void
|
|
59
72
|
|
|
60
73
|
# Starts the server's main accept loop in a new thread.
|
|
61
74
|
#
|
|
62
75
|
# The accept loop polls listening sockets for ready connections and accepts
|
|
63
|
-
# them when
|
|
64
|
-
#
|
|
65
|
-
# worker
|
|
76
|
+
# them when the reactor backlog is under the backpressure threshold. On
|
|
77
|
+
# Linux with BPF-directed dispatch active, a companion thread publishes
|
|
78
|
+
# this worker's backlog to the BPF map.
|
|
66
79
|
#
|
|
67
80
|
# @return [Thread] the thread running the accept loop
|
|
68
81
|
#
|
|
@@ -71,8 +84,9 @@ module Raptor
|
|
|
71
84
|
|
|
72
85
|
# Gracefully shuts down the server.
|
|
73
86
|
#
|
|
74
|
-
# Stops accepting new connections and closes all listening sockets.
|
|
75
|
-
#
|
|
87
|
+
# Stops accepting new connections and closes all listening sockets. When
|
|
88
|
+
# `drain_accept_queue` is enabled, dispatches every connection already in
|
|
89
|
+
# the kernel accept queue before closing the listeners.
|
|
76
90
|
#
|
|
77
91
|
# @return [void]
|
|
78
92
|
#
|
|
@@ -81,6 +95,22 @@ module Raptor
|
|
|
81
95
|
|
|
82
96
|
private
|
|
83
97
|
|
|
98
|
+
# Starts a background thread that publishes this worker's reactor
|
|
99
|
+
# backlog to the BPF map for load-aware dispatch.
|
|
100
|
+
#
|
|
101
|
+
# @return [void]
|
|
102
|
+
#
|
|
103
|
+
# @rbs () -> void
|
|
104
|
+
def spawn_load_reporter: () -> void
|
|
105
|
+
|
|
106
|
+
# Dispatches every connection already in the kernel accept queue for each
|
|
107
|
+
# listener until all are drained.
|
|
108
|
+
#
|
|
109
|
+
# @return [void]
|
|
110
|
+
#
|
|
111
|
+
# @rbs () -> void
|
|
112
|
+
def drain_accept_queue: () -> void
|
|
113
|
+
|
|
84
114
|
# Accepts a connection from the given listener and dispatches it.
|
|
85
115
|
#
|
|
86
116
|
# For SSL listeners the TLS handshake is offloaded to the thread pool so
|
|
@@ -90,11 +120,10 @@ module Raptor
|
|
|
90
120
|
# follow the HTTP/1.1 path.
|
|
91
121
|
#
|
|
92
122
|
# @param listener [TCPServer, UNIXServer, Binder::SslListener] the ready listener
|
|
93
|
-
# @
|
|
94
|
-
# @return [void]
|
|
123
|
+
# @return [Boolean] true if a connection was accepted, false if the listener had nothing to dispatch
|
|
95
124
|
#
|
|
96
|
-
# @rbs (TCPServer | UNIXServer | Binder::SslListener listener
|
|
97
|
-
def accept_connection: (TCPServer | UNIXServer | Binder::SslListener listener
|
|
125
|
+
# @rbs (TCPServer | UNIXServer | Binder::SslListener listener) -> bool
|
|
126
|
+
def accept_connection: (TCPServer | UNIXServer | Binder::SslListener listener) -> bool
|
|
98
127
|
|
|
99
128
|
# Performs the TLS handshake for an accepted SSL connection and dispatches
|
|
100
129
|
# it through the HTTP/2 or HTTP/1.1 path. The handshake is bounded by
|
|
@@ -103,11 +132,10 @@ module Raptor
|
|
|
103
132
|
# @param listener [Binder::SslListener] the SSL listener that accepted the connection
|
|
104
133
|
# @param tcp_client [TCPSocket] the accepted TCP socket
|
|
105
134
|
# @param remote_addr [String] the client's IP address
|
|
106
|
-
# @param reactor [Reactor] the reactor to dispatch the connection to
|
|
107
135
|
# @return [void]
|
|
108
136
|
#
|
|
109
|
-
# @rbs (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr
|
|
110
|
-
def dispatch_ssl_connection: (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr
|
|
137
|
+
# @rbs (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr) -> void
|
|
138
|
+
def dispatch_ssl_connection: (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr) -> void
|
|
111
139
|
|
|
112
140
|
# Drives a non-blocking SSL handshake to completion, bounded by the
|
|
113
141
|
# configured first-data timeout. Returns true on success, false on
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Generated from lib/raptor/systemd.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Integration with systemd's service notification protocol and
|
|
5
|
+
# socket-activation file descriptors.
|
|
6
|
+
module Systemd
|
|
7
|
+
LISTEN_FDS_START: ::Integer
|
|
8
|
+
|
|
9
|
+
LISTEN_FDNAMES_ENV: ::String
|
|
10
|
+
|
|
11
|
+
LISTEN_FDS_ENV: ::String
|
|
12
|
+
|
|
13
|
+
LISTEN_PID_ENV: ::String
|
|
14
|
+
|
|
15
|
+
NOTIFY_SOCKET_ENV: ::String
|
|
16
|
+
|
|
17
|
+
# Sends `message` to the systemd notification socket, returning true on
|
|
18
|
+
# success and false when the socket is unset or the send fails.
|
|
19
|
+
#
|
|
20
|
+
# @param message [String] notify protocol payload, e.g. "READY=1"
|
|
21
|
+
# @return [Boolean]
|
|
22
|
+
#
|
|
23
|
+
# @rbs (String message) -> bool
|
|
24
|
+
def self.notify: (String message) -> bool
|
|
25
|
+
|
|
26
|
+
# Returns the file descriptors passed in via socket activation, or an
|
|
27
|
+
# empty array when systemd has not exported any.
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<Integer>]
|
|
30
|
+
#
|
|
31
|
+
# @rbs () -> Array[Integer]
|
|
32
|
+
def self.listen_fds: () -> Array[Integer]
|
|
33
|
+
|
|
34
|
+
# Clears the socket-activation environment variables so children don't
|
|
35
|
+
# act on stale values.
|
|
36
|
+
#
|
|
37
|
+
# @return [void]
|
|
38
|
+
#
|
|
39
|
+
# @rbs () -> void
|
|
40
|
+
def self.clear_listen_env: () -> void
|
|
41
|
+
end
|
|
42
|
+
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.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -93,6 +93,20 @@ dependencies:
|
|
|
93
93
|
- - ">="
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: libbpf-ruby
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
96
110
|
email:
|
|
97
111
|
- djry1999@gmail.com
|
|
98
112
|
executables:
|
|
@@ -100,45 +114,58 @@ executables:
|
|
|
100
114
|
extensions:
|
|
101
115
|
- ext/raptor_http/extconf.rb
|
|
102
116
|
- ext/raptor_http2/extconf.rb
|
|
117
|
+
- ext/raptor_native/extconf.rb
|
|
103
118
|
extra_rdoc_files: []
|
|
104
119
|
files:
|
|
105
120
|
- ".buildkite/pipeline.yml"
|
|
121
|
+
- ".dockerignore"
|
|
106
122
|
- ".mise.toml"
|
|
107
123
|
- Brewfile
|
|
108
124
|
- CHANGELOG.md
|
|
109
125
|
- CODE_OF_CONDUCT.md
|
|
126
|
+
- Dockerfile
|
|
110
127
|
- LICENSE.txt
|
|
111
128
|
- README.md
|
|
112
129
|
- Rakefile
|
|
130
|
+
- docs/raptor-vs-puma.md
|
|
113
131
|
- exe/raptor
|
|
132
|
+
- ext/raptor_bpf/reuseport_select.bpf.c
|
|
114
133
|
- ext/raptor_http/extconf.rb
|
|
115
134
|
- ext/raptor_http/raptor_http.c
|
|
116
135
|
- ext/raptor_http2/extconf.rb
|
|
117
136
|
- ext/raptor_http2/huffman_table.h
|
|
118
137
|
- ext/raptor_http2/raptor_http2.c
|
|
138
|
+
- ext/raptor_native/extconf.rb
|
|
139
|
+
- ext/raptor_native/raptor_native.c
|
|
119
140
|
- lib/rackup/handler/raptor.rb
|
|
120
141
|
- lib/raptor.rb
|
|
121
142
|
- lib/raptor/binder.rb
|
|
122
143
|
- lib/raptor/cli.rb
|
|
123
144
|
- lib/raptor/cluster.rb
|
|
145
|
+
- lib/raptor/http.rb
|
|
146
|
+
- lib/raptor/http1.rb
|
|
124
147
|
- lib/raptor/http2.rb
|
|
125
148
|
- lib/raptor/log.rb
|
|
126
149
|
- lib/raptor/reactor.rb
|
|
127
|
-
- lib/raptor/
|
|
150
|
+
- lib/raptor/reuseport_bpf.rb
|
|
128
151
|
- lib/raptor/server.rb
|
|
129
152
|
- lib/raptor/stats.rb
|
|
153
|
+
- lib/raptor/systemd.rb
|
|
130
154
|
- lib/raptor/version.rb
|
|
131
155
|
- sig/generated/rackup/handler/raptor.rbs
|
|
132
156
|
- sig/generated/raptor.rbs
|
|
133
157
|
- sig/generated/raptor/binder.rbs
|
|
134
158
|
- sig/generated/raptor/cli.rbs
|
|
135
159
|
- sig/generated/raptor/cluster.rbs
|
|
160
|
+
- sig/generated/raptor/http.rbs
|
|
161
|
+
- sig/generated/raptor/http1.rbs
|
|
136
162
|
- sig/generated/raptor/http2.rbs
|
|
137
163
|
- sig/generated/raptor/log.rbs
|
|
138
164
|
- sig/generated/raptor/reactor.rbs
|
|
139
|
-
- sig/generated/raptor/
|
|
165
|
+
- sig/generated/raptor/reuseport_bpf.rbs
|
|
140
166
|
- sig/generated/raptor/server.rbs
|
|
141
167
|
- sig/generated/raptor/stats.rbs
|
|
168
|
+
- sig/generated/raptor/systemd.rbs
|
|
142
169
|
- sig/generated/raptor/version.rbs
|
|
143
170
|
homepage: https://github.com/joshuay03/raptor
|
|
144
171
|
licenses:
|