Class: PumaPlus::ConfigFile
- Inherits:
-
Object
- Object
- PumaPlus::ConfigFile
- Defined in:
- lib/puma_plus/config_file.rb
Overview
The config-file DSL, evaluated against a plain Ruby file the way puma evaluates config/puma.rb.
A Ruby file rather than YAML because the interesting things are not values.
Lifecycle hooks are blocks, worker counts are routinely computed from
Etc.nprocessors or an env var, and a config that can branch on
environment is the reason anyone tolerates a config file at all.
Names follow puma wherever the concept exists, so a config can be ported by deleting the lines that no longer apply rather than rewritten. Where puma has no equivalent -- autoscaling, Ractors, HTTP/2 and /3 -- the names are ours.
Constant Summary collapse
- IGNORED =
Options a puma config sets that puma-plus has no equivalent for, mapped to why. Accepted and ignored with a warning rather than raising: a config ported from puma should boot, and then tell you what it dropped.
{ preload_app!: "puma-plus always preloads; the shepherd loads the app once and forks", prune_bundler: "the Go server is not a gem, so there is no bundler to prune", queue_requests: "requests are always queued, in Go -- that is the whole design", wait_for_less_busy_worker: "Go dispatches to an idle worker by construction", fork_worker: "not implemented", nakayoshi_fork: "not implemented", set_remote_address: "Go builds REMOTE_ADDR when it constructs the env" }.freeze
Instance Attribute Summary collapse
-
#hooks ⇒ Object
readonly
Returns the value of attribute hooks.
-
#warnings ⇒ Object
readonly
Returns the value of attribute warnings.
Class Method Summary collapse
Instance Method Summary collapse
- #acquire_timeout(d) ⇒ Object
-
#activate_control_app(url = "tcp://127.0.0.1:9293", _opts = {}) ⇒ Object
Where /stats, /metrics and /health are served.
-
#autoscale(min: nil, max: nil, target_queue_p95: nil, enabled: true) ⇒ Object
autoscale min: 1, max: 8, target_queue_p95: "25ms".
-
#before_fork(&blk) ⇒ Object
--- lifecycle hooks ------------------------------------------------.
-
#bind(url) ⇒ Object
bind "tcp://0.0.0.0:9292" bind "ssl://0.0.0.0:9443".
- #debug_headers(enabled = true) ⇒ Object
- #decision_log(path) ⇒ Object
- #directory(dir) ⇒ Object
- #environment(env) ⇒ Object
-
#h2c(enabled = true) ⇒ Object
HTTP/2 cleartext on the main listener.
-
#http3(addr) ⇒ Object
HTTP/3 needs its own address because QUIC is UDP.
-
#initialize(options, path: nil) ⇒ ConfigFile
constructor
A new instance of ConfigFile.
- #max_connections(n) ⇒ Object
- #mem_limit(mb) ⇒ Object
- #on_worker_boot(&blk) ⇒ Object
- #on_worker_shutdown(&blk) ⇒ Object
- #pidfile(path) ⇒ Object
- #port(port, host = nil) ⇒ Object
-
#rackup(path) ⇒ Object
--- app ------------------------------------------------------------.
-
#ractors(count) ⇒ Object
Serve from N Ractors in one process instead of threads across forks.
-
#ssl_bind(host, port, opts = {}) ⇒ Object
ssl_bind "0.0.0.0", 9443, cert: "...", key: "...".
- #tag(name) ⇒ Object
-
#threads(min, max = min) ⇒ Object
threads min, max.
-
#tls_cert(cert, key) ⇒ Object
Certificate and key paths for the TLS and HTTP/3 listeners.
- #tls_hosts(*names) ⇒ Object
- #websockets(enabled = true) ⇒ Object
- #webtransport(enabled = true) ⇒ Object
-
#workers(count) ⇒ Object
--- concurrency ----------------------------------------------------.
Constructor Details
#initialize(options, path: nil) ⇒ ConfigFile
Returns a new instance of ConfigFile.
71 72 73 74 75 76 |
# File 'lib/puma_plus/config_file.rb', line 71 def initialize(, path: nil) @options = @path = path @hooks = Hash.new { |h, k| h[k] = [] } @warnings = [] end |
Instance Attribute Details
#hooks ⇒ Object (readonly)
Returns the value of attribute hooks.
78 79 80 |
# File 'lib/puma_plus/config_file.rb', line 78 def hooks @hooks end |
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
78 79 80 |
# File 'lib/puma_plus/config_file.rb', line 78 def warnings @warnings end |
Class Method Details
.load(path, options) ⇒ Object
80 81 82 83 84 |
# File 'lib/puma_plus/config_file.rb', line 80 def self.load(path, ) dsl = new(, path: path) dsl.instance_eval(File.read(path), path, 1) dsl end |
Instance Method Details
#acquire_timeout(d) ⇒ Object
177 |
# File 'lib/puma_plus/config_file.rb', line 177 def acquire_timeout(d) = set(:acquire_timeout, duration(d, "acquire_timeout")) |
#activate_control_app(url = "tcp://127.0.0.1:9293", _opts = {}) ⇒ Object
Where /stats, /metrics and /health are served.
188 189 190 |
# File 'lib/puma_plus/config_file.rb', line 188 def activate_control_app(url = "tcp://127.0.0.1:9293", _opts = {}) set :control, Address.host_port(url, 9293, "activate_control_app") end |
#autoscale(min: nil, max: nil, target_queue_p95: nil, enabled: true) ⇒ Object
autoscale min: 1, max: 8, target_queue_p95: "25ms"
168 169 170 171 172 173 |
# File 'lib/puma_plus/config_file.rb', line 168 def autoscale(min: nil, max: nil, target_queue_p95: nil, enabled: true) set :autoscale, !!enabled set :min_workers, Integer(min) if min set :max_workers, Integer(max) if max set :target_queue_p95, duration(target_queue_p95, "target_queue_p95") if target_queue_p95 end |
#before_fork(&blk) ⇒ Object
--- lifecycle hooks ------------------------------------------------
Blocks, so they cannot be translated into flags for the Go process. The worker re-reads this same config file and runs them itself; the launcher only records that they exist so it can pass the path along.
202 |
# File 'lib/puma_plus/config_file.rb', line 202 def before_fork(&blk) = @hooks[:before_fork] << blk |
#bind(url) ⇒ Object
bind "tcp://0.0.0.0:9292" bind "ssl://0.0.0.0:9443"
Unix sockets are deliberately unsupported for the client listener: the unix socket in this design is how workers dial in, and letting a config point a public listener at one invites confusing the two.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/puma_plus/config_file.rb', line 94 def bind(url) uri = begin URI.parse(url) rescue URI::Error => e raise ConfigError, "bind #{url.inspect}: #{e.}" end case uri.scheme when "tcp", "http" set :listen, "#{uri.host}:#{uri.port || 9292}" when "ssl", "https" set :listen_tls, "#{uri.host}:#{uri.port || 9443}" apply_ssl_params(URI.decode_www_form(uri.query.to_s).to_h, url) when "unix" raise ConfigError, "bind #{url.inspect}: unix sockets are not supported for " \ "the HTTP listener (the unix socket is how workers dial in)" else raise ConfigError, "bind #{url.inspect}: unknown scheme #{uri.scheme.inspect}" end end |
#debug_headers(enabled = true) ⇒ Object
194 |
# File 'lib/puma_plus/config_file.rb', line 194 def debug_headers(enabled = true) = set(:debug_headers, !!enabled) |
#decision_log(path) ⇒ Object
176 |
# File 'lib/puma_plus/config_file.rb', line 176 def decision_log(path) = set(:decision_log, path.to_s) |
#directory(dir) ⇒ Object
183 |
# File 'lib/puma_plus/config_file.rb', line 183 def directory(dir) = set(:directory, File.(dir.to_s)) |
#environment(env) ⇒ Object
182 |
# File 'lib/puma_plus/config_file.rb', line 182 def environment(env) = set(:environment, env.to_s) |
#h2c(enabled = true) ⇒ Object
HTTP/2 cleartext on the main listener. Nothing in puma to mirror.
119 |
# File 'lib/puma_plus/config_file.rb', line 119 def h2c(enabled = true) = set(:h2c, !!enabled) |
#http3(addr) ⇒ Object
HTTP/3 needs its own address because QUIC is UDP.
122 |
# File 'lib/puma_plus/config_file.rb', line 122 def http3(addr) = set(:listen_h3, addr.to_s) |
#max_connections(n) ⇒ Object
163 |
# File 'lib/puma_plus/config_file.rb', line 163 def max_connections(n) = set(:max_conns, Integer(n)) |
#mem_limit(mb) ⇒ Object
175 |
# File 'lib/puma_plus/config_file.rb', line 175 def mem_limit(mb) = set(:mem_limit_mb, Integer(mb)) |
#on_worker_boot(&blk) ⇒ Object
203 |
# File 'lib/puma_plus/config_file.rb', line 203 def on_worker_boot(&blk) = @hooks[:on_worker_boot] << blk |
#on_worker_shutdown(&blk) ⇒ Object
204 |
# File 'lib/puma_plus/config_file.rb', line 204 def on_worker_shutdown(&blk) = @hooks[:on_worker_shutdown] << blk |
#pidfile(path) ⇒ Object
185 |
# File 'lib/puma_plus/config_file.rb', line 185 def pidfile(path) = set(:pidfile, path.to_s) |
#port(port, host = nil) ⇒ Object
114 115 116 |
# File 'lib/puma_plus/config_file.rb', line 114 def port(port, host = nil) set :listen, "#{host || '0.0.0.0'}:#{Integer(port)}" end |
#rackup(path) ⇒ Object
--- app ------------------------------------------------------------
181 |
# File 'lib/puma_plus/config_file.rb', line 181 def rackup(path) = set(:app, path.to_s) |
#ractors(count) ⇒ Object
Serve from N Ractors in one process instead of threads across forks.
161 |
# File 'lib/puma_plus/config_file.rb', line 161 def ractors(count) = set(:ractors, Integer(count)) |
#ssl_bind(host, port, opts = {}) ⇒ Object
ssl_bind "0.0.0.0", 9443, cert: "...", key: "..."
puma's signature, so an existing ssl_bind line ports unchanged. The
equivalent query-string form on bind works too, since both end up here.
130 131 132 133 |
# File 'lib/puma_plus/config_file.rb', line 130 def ssl_bind(host, port, opts = {}) set :listen_tls, "#{host}:#{Integer(port)}" apply_ssl_params(opts.transform_keys(&:to_s), "ssl_bind") end |
#tag(name) ⇒ Object
184 |
# File 'lib/puma_plus/config_file.rb', line 184 def tag(name) = set(:tag, name.to_s) |
#threads(min, max = min) ⇒ Object
threads min, max
puma-plus has no thread pool to grow and shrink: a thread is a connection to Go, dialed at boot and held. So only the max is meaningful, and a config that asks for a range gets told which number was used rather than silently having one picked.
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/puma_plus/config_file.rb', line 148 def threads(min, max = min) min = Integer(min) max = Integer(max) raise ConfigError, "threads: min (#{min}) must be <= max (#{max})" if min > max if min != max @warnings << "threads #{min},#{max}: puma-plus holds a fixed number of " \ "worker connections, so #{max} is used and #{min} ignored" end set :threads, max end |
#tls_cert(cert, key) ⇒ Object
Certificate and key paths for the TLS and HTTP/3 listeners.
136 |
# File 'lib/puma_plus/config_file.rb', line 136 def tls_cert(cert, key) = (set(:tls_cert, (cert)); set(:tls_key, (key))) |
#tls_hosts(*names) ⇒ Object
124 |
# File 'lib/puma_plus/config_file.rb', line 124 def tls_hosts(*names) = set(:tls_hosts, names.flatten.join(",")) |
#websockets(enabled = true) ⇒ Object
192 |
# File 'lib/puma_plus/config_file.rb', line 192 def websockets(enabled = true) = set(:websockets, !!enabled) |
#webtransport(enabled = true) ⇒ Object
193 |
# File 'lib/puma_plus/config_file.rb', line 193 def webtransport(enabled = true) = set(:webtransport, !!enabled) |
#workers(count) ⇒ Object
--- concurrency ----------------------------------------------------
140 |
# File 'lib/puma_plus/config_file.rb', line 140 def workers(count) = set(:workers, Integer(count)) |