Module: Hyperion::Adapter::Rack
- Defined in:
- lib/hyperion/adapter/rack.rb
Overview
NOTE: this is Hyperion::Adapter::Rack, not the Rack gem. Reference the Rack gem as ::Rack inside this module if needed.
Constant Summary collapse
- HTTP_KEY_CACHE =
Pre-frozen mapping for the 16 most common HTTP request headers. Skips the per-request ‘“HTTP_#’_’)”‘ allocation (5–15 string ops per request × N headers). Uncached header names fall back to the dynamic computation. Keys are lowercased to match the parser’s normalisation.
{ 'host' => 'HTTP_HOST', 'user-agent' => 'HTTP_USER_AGENT', 'accept' => 'HTTP_ACCEPT', 'accept-encoding' => 'HTTP_ACCEPT_ENCODING', 'accept-language' => 'HTTP_ACCEPT_LANGUAGE', 'connection' => 'HTTP_CONNECTION', 'content-type' => 'HTTP_CONTENT_TYPE', 'content-length' => 'HTTP_CONTENT_LENGTH', 'cookie' => 'HTTP_COOKIE', 'authorization' => 'HTTP_AUTHORIZATION', 'cache-control' => 'HTTP_CACHE_CONTROL', 'referer' => 'HTTP_REFERER', 'origin' => 'HTTP_ORIGIN', 'x-forwarded-for' => 'HTTP_X_FORWARDED_FOR', 'x-forwarded-proto' => 'HTTP_X_FORWARDED_PROTO', 'x-real-ip' => 'HTTP_X_REAL_IP' }.freeze
- ENV_POOL =
Hyperion::Pool.new( max_size: 256, factory: -> { {} }, reset: ->(env) { env.clear } )
- INPUT_POOL =
Hyperion::Pool.new( max_size: 256, factory: -> { StringIO.new }, reset: lambda { |io| io.string = +'' io.rewind } )
Class Method Summary collapse
-
.c_upcase_available? ⇒ Boolean
Whether Hyperion::CParser.upcase_underscore is available.
- .call(app, request) ⇒ Object
-
.warmup_pool(count = 8) ⇒ Object
Pre-allocate ‘n` env-hash and rack-input objects in master before fork.
Class Method Details
.c_upcase_available? ⇒ Boolean
Whether Hyperion::CParser.upcase_underscore is available. Probed lazily at first use (CParser is required after this file, so an eager check at load time would always be false). Memoised in a class-level ivar to keep the hot path branchless.
55 56 57 58 59 60 |
# File 'lib/hyperion/adapter/rack.rb', line 55 def self.c_upcase_available? return @c_upcase_available unless @c_upcase_available.nil? @c_upcase_available = defined?(::Hyperion::CParser) && ::Hyperion::CParser.respond_to?(:upcase_underscore) end |
.call(app, request) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/hyperion/adapter/rack.rb', line 77 def call(app, request) env, input = build_env(request) status, headers, body = app.call(env) [status, headers, body] rescue StandardError => e Hyperion.metrics.increment(:app_errors) Hyperion.logger.error do { message: 'app raised', error: e., error_class: e.class.name, backtrace: (e.backtrace || []).first(20).join(' | ') } end [500, { 'content-type' => 'text/plain' }, ['Internal Server Error']] ensure # Return env + input to pools after the response has been fully # iterated by the writer. We can't release here because Rack body # is iterated lazily — release happens after the writer. # For Phase 5 simplicity we release synchronously since the writer # buffers fully. Phase 7 (HTTP/2 streaming) will revisit. ENV_POOL.release(env) if env INPUT_POOL.release(input) if input end |
.warmup_pool(count = 8) ⇒ Object
Pre-allocate ‘n` env-hash and rack-input objects in master before fork. Children inherit the populated free-list via copy-on-write —the hash slots stay shared until a request mutates them. Eliminates the first-N-requests allocation tax that every fresh worker would otherwise pay on cold start. Idempotent: safe to call multiple times; the pool simply caps at its configured `max_size`.
69 70 71 72 73 74 75 |
# File 'lib/hyperion/adapter/rack.rb', line 69 def warmup_pool(count = 8) warmed_envs = Array.new(count) { ENV_POOL.acquire } warmed_inputs = Array.new(count) { INPUT_POOL.acquire } warmed_envs.each { |e| ENV_POOL.release(e) } warmed_inputs.each { |i| INPUT_POOL.release(i) } nil end |