hyperion-rb 1.6.2 → 2.10.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/CHANGELOG.md +4563 -0
- data/README.md +189 -13
- data/ext/hyperion_h2_codec/Cargo.lock +7 -0
- data/ext/hyperion_h2_codec/Cargo.toml +33 -0
- data/ext/hyperion_h2_codec/extconf.rb +73 -0
- data/ext/hyperion_h2_codec/src/frames.rs +140 -0
- data/ext/hyperion_h2_codec/src/hpack/huffman.rs +161 -0
- data/ext/hyperion_h2_codec/src/hpack.rs +457 -0
- data/ext/hyperion_h2_codec/src/lib.rs +296 -0
- data/ext/hyperion_http/extconf.rb +28 -0
- data/ext/hyperion_http/h2_codec_glue.c +408 -0
- data/ext/hyperion_http/page_cache.c +1125 -0
- data/ext/hyperion_http/parser.c +473 -38
- data/ext/hyperion_http/sendfile.c +982 -0
- data/ext/hyperion_http/websocket.c +493 -0
- data/ext/hyperion_io_uring/Cargo.lock +33 -0
- data/ext/hyperion_io_uring/Cargo.toml +34 -0
- data/ext/hyperion_io_uring/extconf.rb +74 -0
- data/ext/hyperion_io_uring/src/lib.rs +316 -0
- data/lib/hyperion/adapter/rack.rb +370 -42
- data/lib/hyperion/admin_listener.rb +207 -0
- data/lib/hyperion/admin_middleware.rb +36 -7
- data/lib/hyperion/cli.rb +310 -11
- data/lib/hyperion/config.rb +440 -14
- data/lib/hyperion/connection.rb +679 -22
- data/lib/hyperion/deprecations.rb +81 -0
- data/lib/hyperion/dispatch_mode.rb +165 -0
- data/lib/hyperion/fiber_local.rb +75 -13
- data/lib/hyperion/h2_admission.rb +77 -0
- data/lib/hyperion/h2_codec.rb +452 -0
- data/lib/hyperion/http/page_cache.rb +122 -0
- data/lib/hyperion/http/sendfile.rb +696 -0
- data/lib/hyperion/http2/native_hpack_adapter.rb +70 -0
- data/lib/hyperion/http2_handler.rb +368 -9
- data/lib/hyperion/io_uring.rb +317 -0
- data/lib/hyperion/lint_wrapper_pool.rb +126 -0
- data/lib/hyperion/master.rb +96 -9
- data/lib/hyperion/metrics/path_templater.rb +68 -0
- data/lib/hyperion/metrics.rb +256 -0
- data/lib/hyperion/prometheus_exporter.rb +150 -0
- data/lib/hyperion/request.rb +13 -0
- data/lib/hyperion/response_writer.rb +477 -16
- data/lib/hyperion/runtime.rb +195 -0
- data/lib/hyperion/server/route_table.rb +179 -0
- data/lib/hyperion/server.rb +519 -55
- data/lib/hyperion/static_preload.rb +133 -0
- data/lib/hyperion/thread_pool.rb +61 -7
- data/lib/hyperion/tls.rb +343 -1
- data/lib/hyperion/version.rb +1 -1
- data/lib/hyperion/websocket/close_codes.rb +71 -0
- data/lib/hyperion/websocket/connection.rb +876 -0
- data/lib/hyperion/websocket/frame.rb +356 -0
- data/lib/hyperion/websocket/handshake.rb +525 -0
- data/lib/hyperion/worker.rb +111 -9
- data/lib/hyperion.rb +137 -3
- metadata +50 -1
data/lib/hyperion.rb
CHANGED
|
@@ -3,22 +3,48 @@
|
|
|
3
3
|
require_relative 'hyperion/version'
|
|
4
4
|
require_relative 'hyperion/logger'
|
|
5
5
|
require_relative 'hyperion/metrics'
|
|
6
|
+
require_relative 'hyperion/runtime'
|
|
7
|
+
require_relative 'hyperion/deprecations'
|
|
8
|
+
require_relative 'hyperion/dispatch_mode'
|
|
6
9
|
require_relative 'hyperion/config'
|
|
10
|
+
require_relative 'hyperion/h2_admission'
|
|
7
11
|
|
|
8
12
|
module Hyperion
|
|
9
13
|
class Error < StandardError; end
|
|
10
14
|
class ParseError < Error; end
|
|
11
15
|
class UnsupportedError < Error; end
|
|
12
16
|
|
|
17
|
+
# Probe table for fiber-cooperative I/O libraries. 1.7.0 expanded
|
|
18
|
+
# the validation surface (RFC A9): `async_io: true` now requires at
|
|
19
|
+
# least one of these to be loaded, otherwise CLI bootstrap raises
|
|
20
|
+
# at `Hyperion.validate_async_io_loaded_libs!`. The CLI's pre-fork
|
|
21
|
+
# `warn_orphan_async_io` (1.6.1) still emits a soft warn for the
|
|
22
|
+
# nil-default case so existing operators see the same advisory log.
|
|
23
|
+
FIBER_IO_PROBES = {
|
|
24
|
+
'hyperion-async-pg' => -> { defined?(::Hyperion::AsyncPg) },
|
|
25
|
+
'async-redis' => -> { defined?(::Async::Redis) },
|
|
26
|
+
'async-http' => -> { defined?(::Async::HTTP) }
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
13
29
|
class << self
|
|
30
|
+
# 2.0.0: legacy module-level `Hyperion.metrics =` / `Hyperion.logger =`
|
|
31
|
+
# SETTERS are removed. The getters stay as Runtime.default delegators —
|
|
32
|
+
# they're the canonical REPL convenience — and assignment now happens
|
|
33
|
+
# via the Runtime API:
|
|
34
|
+
#
|
|
35
|
+
# Hyperion::Runtime.default.metrics = MyAdapter.new # mutate default
|
|
36
|
+
# server = Hyperion::Server.new(app:, runtime: Hyperion::Runtime.new(metrics: …))
|
|
37
|
+
#
|
|
38
|
+
# The 1.8.0 deprecation warns called this out for one full release;
|
|
39
|
+
# in-tree spec rewrites flipped to `Runtime.default.metrics =` already.
|
|
14
40
|
def logger
|
|
15
|
-
|
|
41
|
+
Runtime.default.logger
|
|
16
42
|
end
|
|
17
43
|
|
|
18
|
-
attr_writer :
|
|
44
|
+
attr_writer :log_requests
|
|
19
45
|
|
|
20
46
|
def metrics
|
|
21
|
-
|
|
47
|
+
Runtime.default.metrics
|
|
22
48
|
end
|
|
23
49
|
|
|
24
50
|
def stats
|
|
@@ -75,6 +101,95 @@ module Hyperion
|
|
|
75
101
|
# with a warn log: warmup is an optimization, not a correctness gate.
|
|
76
102
|
# If, for instance, OpenSSL can't be required in some odd environment,
|
|
77
103
|
# we'd rather start cold than refuse to boot.
|
|
104
|
+
# PID of the Hyperion master process. Writable so the master records its
|
|
105
|
+
# own PID at boot; readable everywhere so AdminMiddleware (and other
|
|
106
|
+
# would-be signallers) can target the master regardless of context.
|
|
107
|
+
#
|
|
108
|
+
# Why not `Process.ppid`? Two reasons:
|
|
109
|
+
#
|
|
110
|
+
# 1. In single-worker mode, the "master" and "worker" are the same
|
|
111
|
+
# process; `Process.ppid` points to the shell / init that launched
|
|
112
|
+
# hyperion, NOT to ourselves.
|
|
113
|
+
# 2. When the master runs as PID 1 inside containerd / Docker (the
|
|
114
|
+
# default for `hyperion` as a container CMD), `Process.ppid` from a
|
|
115
|
+
# worker is `1` — but the worker IS a child of PID 1, so `kill`ing
|
|
116
|
+
# ppid signals the master correctly only by accident, and the
|
|
117
|
+
# pre-1.6.3 fallback `ppid > 1 ? ppid : Process.pid` would
|
|
118
|
+
# MIS-target the worker itself. (Repro: `docker run -e
|
|
119
|
+
# HYPERION_ADMIN_TOKEN=… hyperion` then `curl -X POST /-/quit` —
|
|
120
|
+
# response says draining, nothing happens.)
|
|
121
|
+
#
|
|
122
|
+
# The master sets this at boot (cluster: Master#run, single: CLI.run_single)
|
|
123
|
+
# AND exports `HYPERION_MASTER_PID` into ENV so forked workers read the
|
|
124
|
+
# correct value via copy-on-write. The reader prefers the in-process
|
|
125
|
+
# ivar (faster) and falls back to ENV (cross-fork) and finally to
|
|
126
|
+
# `Process.pid` (last-resort: someone constructed AdminMiddleware before
|
|
127
|
+
# the master booted, or in a non-Hyperion test context).
|
|
128
|
+
def master_pid
|
|
129
|
+
return @master_pid if @master_pid
|
|
130
|
+
|
|
131
|
+
env = ENV['HYPERION_MASTER_PID']
|
|
132
|
+
env_pid = env && env =~ /\A\d+\z/ ? env.to_i : nil
|
|
133
|
+
env_pid&.positive? ? env_pid : Process.pid
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Record the master PID and export it for forked workers. Called once
|
|
137
|
+
# by the master at boot. Workers inherit ENV via fork; the worker's own
|
|
138
|
+
# `master_pid` ivar stays nil and its reader falls back to ENV.
|
|
139
|
+
def master_pid!(pid = Process.pid)
|
|
140
|
+
@master_pid = pid
|
|
141
|
+
ENV['HYPERION_MASTER_PID'] = pid.to_s
|
|
142
|
+
pid
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns the list of currently-loaded fiber-cooperative I/O
|
|
146
|
+
# libraries. Reads `Hyperion::FIBER_IO_PROBES` via `const_get` so
|
|
147
|
+
# `stub_const('Hyperion::FIBER_IO_PROBES', ...)` works for the
|
|
148
|
+
# strict-validation specs without needing a method-injection seam.
|
|
149
|
+
def fiber_io_libs_loaded
|
|
150
|
+
probes = Hyperion.const_get(:FIBER_IO_PROBES)
|
|
151
|
+
probes.select { |_name, probe| probe.call }.keys
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Strict tri-state validation of `async_io` at warmup time (RFC A9).
|
|
155
|
+
# Run after `Hyperion.warmup!`'s eager-load section so any library
|
|
156
|
+
# that monkey-patches in fiber-cooperative I/O during boot has had
|
|
157
|
+
# the chance to install itself.
|
|
158
|
+
#
|
|
159
|
+
# - `true` → MUST have at least one fiber-IO library loaded; raise
|
|
160
|
+
# ArgumentError otherwise. The error message lists the
|
|
161
|
+
# checked libraries so operators can pick one.
|
|
162
|
+
# - `false` → No fiber-IO library should be loaded; if one is, emit
|
|
163
|
+
# a warn (the operator may still want this for some
|
|
164
|
+
# edge case, so we don't raise).
|
|
165
|
+
# - `nil` → Default. The CLI's existing soft-warn path covers
|
|
166
|
+
# this; warmup is a no-op.
|
|
167
|
+
def validate_async_io_loaded_libs!(setting)
|
|
168
|
+
probes = Hyperion.const_get(:FIBER_IO_PROBES)
|
|
169
|
+
case setting
|
|
170
|
+
when true
|
|
171
|
+
loaded = fiber_io_libs_loaded
|
|
172
|
+
if loaded.empty?
|
|
173
|
+
raise ArgumentError,
|
|
174
|
+
'async_io: true requires a fiber-cooperative I/O library to be loaded ' \
|
|
175
|
+
"(checked: #{probes.keys.join(', ')}); none detected. " \
|
|
176
|
+
'See https://github.com/andrew-woblavobla/hyperion#operator-guidance'
|
|
177
|
+
end
|
|
178
|
+
when false
|
|
179
|
+
loaded = fiber_io_libs_loaded
|
|
180
|
+
unless loaded.empty?
|
|
181
|
+
Hyperion.logger.warn do
|
|
182
|
+
{
|
|
183
|
+
message: 'async_io: false but fiber-cooperative I/O library is loaded',
|
|
184
|
+
loaded: loaded,
|
|
185
|
+
impact: 'the library will not yield to a scheduler under async_io: false; verify this is intentional'
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
|
|
78
193
|
def warmup!
|
|
79
194
|
return if @warmed
|
|
80
195
|
|
|
@@ -97,10 +212,22 @@ module Hyperion
|
|
|
97
212
|
# Subsequent calls hit the per-thread `cached_date` slot in response_writer.
|
|
98
213
|
Time.now.httpdate
|
|
99
214
|
nil
|
|
215
|
+
rescue ArgumentError
|
|
216
|
+
# Strict-validation error from `validate_async_io_loaded_libs!` —
|
|
217
|
+
# propagate so operators see the boot-time abort, not a warn-and-
|
|
218
|
+
# continue.
|
|
219
|
+
raise
|
|
100
220
|
rescue StandardError => e
|
|
101
221
|
Hyperion.logger.warn { { message: 'warmup failed (non-fatal)', error: e.message } }
|
|
102
222
|
nil
|
|
103
223
|
end
|
|
224
|
+
|
|
225
|
+
# Test seam: clear the warmup flag so a fresh `warmup!` call can
|
|
226
|
+
# re-run. Used by the async_io strict-validation specs that need to
|
|
227
|
+
# exercise the raise/warn paths multiple times in one process.
|
|
228
|
+
def reset_warmup!
|
|
229
|
+
@warmed = false
|
|
230
|
+
end
|
|
104
231
|
end
|
|
105
232
|
end
|
|
106
233
|
|
|
@@ -126,9 +253,16 @@ require_relative 'hyperion/fiber_local'
|
|
|
126
253
|
require_relative 'hyperion/request'
|
|
127
254
|
require_relative 'hyperion/parser'
|
|
128
255
|
require_relative 'hyperion/c_parser'
|
|
256
|
+
require_relative 'hyperion/http/sendfile'
|
|
257
|
+
require_relative 'hyperion/http/page_cache'
|
|
258
|
+
require_relative 'hyperion/static_preload'
|
|
129
259
|
require_relative 'hyperion/adapter/rack'
|
|
260
|
+
require_relative 'hyperion/lint_wrapper_pool'
|
|
130
261
|
require_relative 'hyperion/prometheus_exporter'
|
|
131
262
|
require_relative 'hyperion/admin_middleware'
|
|
263
|
+
require_relative 'hyperion/admin_listener'
|
|
264
|
+
require_relative 'hyperion/h2_codec'
|
|
265
|
+
require_relative 'hyperion/io_uring'
|
|
132
266
|
require_relative 'hyperion/response_writer'
|
|
133
267
|
require_relative 'hyperion/thread_pool'
|
|
134
268
|
require_relative 'hyperion/connection'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hyperion-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrey Lobanov
|
|
@@ -83,6 +83,20 @@ dependencies:
|
|
|
83
83
|
- - "<"
|
|
84
84
|
- !ruby/object:Gem::Version
|
|
85
85
|
version: '4.0'
|
|
86
|
+
- !ruby/object:Gem::Dependency
|
|
87
|
+
name: base64
|
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - "~>"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0.2'
|
|
93
|
+
type: :runtime
|
|
94
|
+
prerelease: false
|
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - "~>"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0.2'
|
|
86
100
|
- !ruby/object:Gem::Dependency
|
|
87
101
|
name: rspec
|
|
88
102
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -132,41 +146,76 @@ email:
|
|
|
132
146
|
executables:
|
|
133
147
|
- hyperion
|
|
134
148
|
extensions:
|
|
149
|
+
- ext/hyperion_h2_codec/extconf.rb
|
|
135
150
|
- ext/hyperion_http/extconf.rb
|
|
151
|
+
- ext/hyperion_io_uring/extconf.rb
|
|
136
152
|
extra_rdoc_files: []
|
|
137
153
|
files:
|
|
138
154
|
- CHANGELOG.md
|
|
139
155
|
- LICENSE
|
|
140
156
|
- README.md
|
|
141
157
|
- bin/hyperion
|
|
158
|
+
- ext/hyperion_h2_codec/Cargo.lock
|
|
159
|
+
- ext/hyperion_h2_codec/Cargo.toml
|
|
160
|
+
- ext/hyperion_h2_codec/extconf.rb
|
|
161
|
+
- ext/hyperion_h2_codec/src/frames.rs
|
|
162
|
+
- ext/hyperion_h2_codec/src/hpack.rs
|
|
163
|
+
- ext/hyperion_h2_codec/src/hpack/huffman.rs
|
|
164
|
+
- ext/hyperion_h2_codec/src/lib.rs
|
|
142
165
|
- ext/hyperion_http/extconf.rb
|
|
166
|
+
- ext/hyperion_http/h2_codec_glue.c
|
|
143
167
|
- ext/hyperion_http/llhttp/api.c
|
|
144
168
|
- ext/hyperion_http/llhttp/http.c
|
|
145
169
|
- ext/hyperion_http/llhttp/llhttp.c
|
|
146
170
|
- ext/hyperion_http/llhttp/llhttp.h
|
|
171
|
+
- ext/hyperion_http/page_cache.c
|
|
147
172
|
- ext/hyperion_http/parser.c
|
|
173
|
+
- ext/hyperion_http/sendfile.c
|
|
174
|
+
- ext/hyperion_http/websocket.c
|
|
175
|
+
- ext/hyperion_io_uring/Cargo.lock
|
|
176
|
+
- ext/hyperion_io_uring/Cargo.toml
|
|
177
|
+
- ext/hyperion_io_uring/extconf.rb
|
|
178
|
+
- ext/hyperion_io_uring/src/lib.rs
|
|
148
179
|
- lib/hyperion-rb.rb
|
|
149
180
|
- lib/hyperion.rb
|
|
150
181
|
- lib/hyperion/adapter/rack.rb
|
|
182
|
+
- lib/hyperion/admin_listener.rb
|
|
151
183
|
- lib/hyperion/admin_middleware.rb
|
|
152
184
|
- lib/hyperion/c_parser.rb
|
|
153
185
|
- lib/hyperion/cli.rb
|
|
154
186
|
- lib/hyperion/config.rb
|
|
155
187
|
- lib/hyperion/connection.rb
|
|
188
|
+
- lib/hyperion/deprecations.rb
|
|
189
|
+
- lib/hyperion/dispatch_mode.rb
|
|
156
190
|
- lib/hyperion/fiber_local.rb
|
|
191
|
+
- lib/hyperion/h2_admission.rb
|
|
192
|
+
- lib/hyperion/h2_codec.rb
|
|
193
|
+
- lib/hyperion/http/page_cache.rb
|
|
194
|
+
- lib/hyperion/http/sendfile.rb
|
|
195
|
+
- lib/hyperion/http2/native_hpack_adapter.rb
|
|
157
196
|
- lib/hyperion/http2_handler.rb
|
|
197
|
+
- lib/hyperion/io_uring.rb
|
|
198
|
+
- lib/hyperion/lint_wrapper_pool.rb
|
|
158
199
|
- lib/hyperion/logger.rb
|
|
159
200
|
- lib/hyperion/master.rb
|
|
160
201
|
- lib/hyperion/metrics.rb
|
|
202
|
+
- lib/hyperion/metrics/path_templater.rb
|
|
161
203
|
- lib/hyperion/parser.rb
|
|
162
204
|
- lib/hyperion/pool.rb
|
|
163
205
|
- lib/hyperion/prometheus_exporter.rb
|
|
164
206
|
- lib/hyperion/request.rb
|
|
165
207
|
- lib/hyperion/response_writer.rb
|
|
208
|
+
- lib/hyperion/runtime.rb
|
|
166
209
|
- lib/hyperion/server.rb
|
|
210
|
+
- lib/hyperion/server/route_table.rb
|
|
211
|
+
- lib/hyperion/static_preload.rb
|
|
167
212
|
- lib/hyperion/thread_pool.rb
|
|
168
213
|
- lib/hyperion/tls.rb
|
|
169
214
|
- lib/hyperion/version.rb
|
|
215
|
+
- lib/hyperion/websocket/close_codes.rb
|
|
216
|
+
- lib/hyperion/websocket/connection.rb
|
|
217
|
+
- lib/hyperion/websocket/frame.rb
|
|
218
|
+
- lib/hyperion/websocket/handshake.rb
|
|
170
219
|
- lib/hyperion/worker.rb
|
|
171
220
|
- lib/hyperion/worker_health.rb
|
|
172
221
|
homepage: https://github.com/andrew-woblavobla/hyperion
|