Class: Gritz::Configuration
- Inherits:
-
Object
- Object
- Gritz::Configuration
- Defined in:
- /home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb,
tmp/docs-input/dynamic_api.rb
Overview
Validated startup settings for single-process and supervised servers.
Constant Summary collapse
- DEFAULTS =
{ workers: 0, threads: 16, max_waiting_requests: 64, transport: :native, listener_strategy: :reuseport, bind: "0.0.0.0:50051", admin_bind: "127.0.0.1:9090", fork_mode: :clean, fork_guard: :raise, strict_routes: false, reflection: false, drain_delay: 5.0, shutdown_timeout: 25.0, worker_boot_timeout: 60.0, worker_timeout: 30.0, status_interval: 1.0, min_ready_workers: 1, phased_restart_surge: 1, max_connection_age: 300.0, max_connection_age_grace: 30.0, keepalive_time: 60.0, keepalive_permit_without_calls: true, max_receive_message_size: 4 * 1024 * 1024, max_send_message_size: 4 * 1024 * 1024, max_metadata_size: 8192, metrics_backend: :pipe, log_format: :json, log_redact: [], worker_recycle: {}, tls: {}, pid_file: "", reexec_timeout: 60.0 }.freeze
- ENUMS =
{ transport: %i[native async], listener_strategy: %i[reuseport inherited_fd port_per_worker], fork_mode: %i[clean grpc_fork_support], fork_guard: %i[raise warn off], metrics_backend: %i[pipe otlp mmap], log_format: %i[json logfmt] }.freeze
- HOOKS =
%i[before_fork on_worker_boot on_worker_shutdown].freeze
Instance Attribute Summary collapse
- #admin_bind ⇒ Object
- #bind ⇒ Object
- #controllers ⇒ Object
- #drain_delay ⇒ Object
- #fork_guard ⇒ Object
- #fork_mode ⇒ Object
- #health_checks ⇒ Object readonly
- #keepalive_permit_without_calls ⇒ Object
- #keepalive_time ⇒ Object
- #listener_strategy ⇒ Object
- #log_format ⇒ Object
- #log_redact ⇒ Object
- #max_connection_age ⇒ Object
- #max_connection_age_grace ⇒ Object
- #max_metadata_size ⇒ Object
- #max_receive_message_size ⇒ Object
- #max_send_message_size ⇒ Object
- #max_waiting_requests ⇒ Object
- #metrics_backend ⇒ Object
- #metrics_recorder_factory ⇒ Object
- #middleware ⇒ Object
- #min_ready_workers ⇒ Object
- #phased_restart_surge ⇒ Object
- #pid_file ⇒ Object
- #preload_app ⇒ Object
- #reexec_timeout ⇒ Object
- #reflection ⇒ Object
- #shutdown_timeout ⇒ Object
- #status_interval ⇒ Object
- #strict_routes ⇒ Object
- #threads ⇒ Object
- #tls ⇒ Object
- #transport ⇒ Object
- #worker_boot_timeout ⇒ Object
- #worker_recycle ⇒ Object
- #worker_timeout ⇒ Object
- #workers ⇒ Object
Class Method Summary collapse
-
.load(path: nil, env: ENV, overrides: {}) ⇒ Object
CLI overrides > environment > configuration file > defaults.
- .parse_environment(name, value) ⇒ Object
Instance Method Summary collapse
- #add_hook(name, &block) ⇒ Object
- #add_preloader(&block) ⇒ Object
-
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
- #preload! ⇒ Object
- #preload_app? ⇒ Boolean
- #run_hooks(name, *args) ⇒ Object
- #server_args ⇒ Object
- #validate! ⇒ Object
-
#validate_runtime! ⇒ Object
Fail before allocating transport resources for unsupported release features.
- #validate_single_process! ⇒ Object
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
34 35 36 37 38 39 40 41 42 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 34 def initialize DEFAULTS.each { |name, value| public_send("#{name}=", value.dup) } @controllers = [] @middleware = Middleware::Stack.default @hooks = HOOKS.to_h { |name| [name, []] } @health_checks = {} @preload_app = false @preloaders = [] end |
Instance Attribute Details
#admin_bind ⇒ Object
16 17 18 |
# File 'tmp/docs-input/dynamic_api.rb', line 16 def admin_bind @admin_bind end |
#bind ⇒ Object
14 15 16 |
# File 'tmp/docs-input/dynamic_api.rb', line 14 def bind @bind end |
#controllers ⇒ Object
68 69 70 |
# File 'tmp/docs-input/dynamic_api.rb', line 68 def controllers @controllers end |
#drain_delay ⇒ Object
26 27 28 |
# File 'tmp/docs-input/dynamic_api.rb', line 26 def drain_delay @drain_delay end |
#fork_guard ⇒ Object
20 21 22 |
# File 'tmp/docs-input/dynamic_api.rb', line 20 def fork_guard @fork_guard end |
#fork_mode ⇒ Object
18 19 20 |
# File 'tmp/docs-input/dynamic_api.rb', line 18 def fork_mode @fork_mode end |
#health_checks ⇒ Object (readonly)
32 33 34 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 32 def health_checks @health_checks end |
#keepalive_permit_without_calls ⇒ Object
46 47 48 |
# File 'tmp/docs-input/dynamic_api.rb', line 46 def keepalive_permit_without_calls @keepalive_permit_without_calls end |
#keepalive_time ⇒ Object
44 45 46 |
# File 'tmp/docs-input/dynamic_api.rb', line 44 def keepalive_time @keepalive_time end |
#listener_strategy ⇒ Object
12 13 14 |
# File 'tmp/docs-input/dynamic_api.rb', line 12 def listener_strategy @listener_strategy end |
#log_format ⇒ Object
56 57 58 |
# File 'tmp/docs-input/dynamic_api.rb', line 56 def log_format @log_format end |
#log_redact ⇒ Object
58 59 60 |
# File 'tmp/docs-input/dynamic_api.rb', line 58 def log_redact @log_redact end |
#max_connection_age ⇒ Object
40 41 42 |
# File 'tmp/docs-input/dynamic_api.rb', line 40 def max_connection_age @max_connection_age end |
#max_connection_age_grace ⇒ Object
42 43 44 |
# File 'tmp/docs-input/dynamic_api.rb', line 42 def max_connection_age_grace @max_connection_age_grace end |
#max_metadata_size ⇒ Object
52 53 54 |
# File 'tmp/docs-input/dynamic_api.rb', line 52 def @max_metadata_size end |
#max_receive_message_size ⇒ Object
48 49 50 |
# File 'tmp/docs-input/dynamic_api.rb', line 48 def @max_receive_message_size end |
#max_send_message_size ⇒ Object
50 51 52 |
# File 'tmp/docs-input/dynamic_api.rb', line 50 def @max_send_message_size end |
#max_waiting_requests ⇒ Object
8 9 10 |
# File 'tmp/docs-input/dynamic_api.rb', line 8 def max_waiting_requests @max_waiting_requests end |
#metrics_backend ⇒ Object
54 55 56 |
# File 'tmp/docs-input/dynamic_api.rb', line 54 def metrics_backend @metrics_backend end |
#metrics_recorder_factory ⇒ Object
74 75 76 |
# File 'tmp/docs-input/dynamic_api.rb', line 74 def metrics_recorder_factory @metrics_recorder_factory end |
#middleware ⇒ Object
70 71 72 |
# File 'tmp/docs-input/dynamic_api.rb', line 70 def middleware @middleware end |
#min_ready_workers ⇒ Object
36 37 38 |
# File 'tmp/docs-input/dynamic_api.rb', line 36 def min_ready_workers @min_ready_workers end |
#phased_restart_surge ⇒ Object
38 39 40 |
# File 'tmp/docs-input/dynamic_api.rb', line 38 def phased_restart_surge @phased_restart_surge end |
#pid_file ⇒ Object
64 65 66 |
# File 'tmp/docs-input/dynamic_api.rb', line 64 def pid_file @pid_file end |
#preload_app ⇒ Object
72 73 74 |
# File 'tmp/docs-input/dynamic_api.rb', line 72 def preload_app @preload_app end |
#reexec_timeout ⇒ Object
66 67 68 |
# File 'tmp/docs-input/dynamic_api.rb', line 66 def reexec_timeout @reexec_timeout end |
#reflection ⇒ Object
24 25 26 |
# File 'tmp/docs-input/dynamic_api.rb', line 24 def reflection @reflection end |
#shutdown_timeout ⇒ Object
28 29 30 |
# File 'tmp/docs-input/dynamic_api.rb', line 28 def shutdown_timeout @shutdown_timeout end |
#status_interval ⇒ Object
34 35 36 |
# File 'tmp/docs-input/dynamic_api.rb', line 34 def status_interval @status_interval end |
#strict_routes ⇒ Object
22 23 24 |
# File 'tmp/docs-input/dynamic_api.rb', line 22 def strict_routes @strict_routes end |
#threads ⇒ Object
6 7 8 |
# File 'tmp/docs-input/dynamic_api.rb', line 6 def threads @threads end |
#tls ⇒ Object
62 63 64 |
# File 'tmp/docs-input/dynamic_api.rb', line 62 def tls @tls end |
#transport ⇒ Object
10 11 12 |
# File 'tmp/docs-input/dynamic_api.rb', line 10 def transport @transport end |
#worker_boot_timeout ⇒ Object
30 31 32 |
# File 'tmp/docs-input/dynamic_api.rb', line 30 def worker_boot_timeout @worker_boot_timeout end |
#worker_recycle ⇒ Object
60 61 62 |
# File 'tmp/docs-input/dynamic_api.rb', line 60 def worker_recycle @worker_recycle end |
#worker_timeout ⇒ Object
32 33 34 |
# File 'tmp/docs-input/dynamic_api.rb', line 32 def worker_timeout @worker_timeout end |
#workers ⇒ Object
4 5 6 |
# File 'tmp/docs-input/dynamic_api.rb', line 4 def workers @workers end |
Class Method Details
.load(path: nil, env: ENV, overrides: {}) ⇒ Object
CLI overrides > environment > configuration file > defaults.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 45 def self.load(path: nil, env: ENV, overrides: {}) config = new DSL.new(config).evaluate(path) if path env.each do |key, value| next unless key.start_with?("GRITZ_") next if key == "GRITZ_RELEASE" # Dependency selection in the release workflow, not a runtime setting. name = key.delete_prefix("GRITZ_").downcase.to_sym raise ConfigurationError, "Unknown environment setting #{key}" unless DEFAULTS.key?(name) next if overrides.key?(name) config.public_send("#{name}=", parse_environment(name, value)) end overrides.each { |name, value| config.public_send("#{name}=", value) } config.validate! end |
.parse_environment(name, value) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 62 def self.parse_environment(name, value) case DEFAULTS.fetch(name) when Integer then Integer(value, 10) when Float then Float(value) when Symbol then value.to_sym when Hash, Array then JSON.parse(value, symbolize_names: true) when true, false return true if %w[true 1].include?(value) return false if %w[false 0].include?(value) raise ArgumentError, "expected true or false" else value end rescue ArgumentError, TypeError, JSON::ParserError => e raise ConfigurationError, "Invalid GRITZ_#{name.to_s.upcase}: #{e.}" end |
Instance Method Details
#add_hook(name, &block) ⇒ Object
159 160 161 162 163 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 159 def add_hook(name, &block) raise ConfigurationError, "#{name} requires a block" unless block @hooks.fetch(name) << block end |
#add_preloader(&block) ⇒ Object
149 150 151 152 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 149 def add_preloader(&block) @preload_app = true @preloaders << block if block end |
#preload! ⇒ Object
154 155 156 157 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 154 def preload! @preloaders.each(&:call) Core::LOADER.eager_load end |
#preload_app? ⇒ Boolean
115 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 115 def preload_app? = preload_app |
#run_hooks(name, *args) ⇒ Object
165 166 167 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 165 def run_hooks(name, *args) @hooks.fetch(name).each { |hook| hook.call(*args) } end |
#server_args ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 169 def server_args { "grpc.so_reuseport" => listener_strategy == :reuseport ? 1 : 0, "grpc.max_connection_age_ms" => (max_connection_age * 1000).to_i, "grpc.max_connection_age_grace_ms" => (max_connection_age_grace * 1000).to_i, "grpc.keepalive_time_ms" => (keepalive_time * 1000).to_i, "grpc.keepalive_permit_without_calls" => keepalive_permit_without_calls ? 1 : 0, "grpc.max_receive_message_length" => , "grpc.max_send_message_length" => , "grpc.max_metadata_size" => } end |
#validate! ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 79 def validate! DEFAULTS.each do |name, default| value = public_send(name) valid = case default when Integer then value.is_a?(Integer) && value.between?(name == :workers ? 0 : 1, 2_147_483_647) when Float then value.is_a?(Numeric) && value.real? && value.finite? && value.between?(0, 2_147_483.647) when true, false then [true, false].include?(value) else value.is_a?(default.class) end raise ConfigurationError, "Invalid #{name}: #{value.inspect}" unless valid end %i[shutdown_timeout worker_boot_timeout worker_timeout status_interval reexec_timeout].each do |name| raise ConfigurationError, "#{name} must be positive" unless public_send(name).positive? end ENUMS.each do |name, allowed| raise ConfigurationError, "#{name} must be one of #{allowed.join(', ')}" unless allowed.include?(public_send(name)) end validate_addresses! validate_recycle! validate_tls! raise ConfigurationError, "controllers must be an Array of classes" unless controllers.is_a?(Array) && controllers.all?(Class) raise ConfigurationError, "middleware must be a Stack" unless middleware.is_a?(Middleware::Stack) if metrics_recorder_factory && !metrics_recorder_factory.respond_to?(:call) raise ConfigurationError, "metrics recorder factory must be callable" end raise ConfigurationError, "preload_app must be boolean" unless [true, false].include?(preload_app) unless log_redact.all? { |name| name.is_a?(String) || name.is_a?(Symbol) } raise ConfigurationError, "log_redact must contain metadata names" end unless health_checks.all? { |name, check| (name.is_a?(String) || name.is_a?(Symbol)) && check.respond_to?(:call) } raise ConfigurationError, "health_checks must contain named callbacks" end self end |
#validate_runtime! ⇒ Object
Fail before allocating transport resources for unsupported release features.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 118 def validate_runtime! validate! supported = transport == :native ? %i[reuseport] : %i[reuseport inherited_fd] raise ConfigurationError, "#{transport} does not support listener_strategy #{listener_strategy}" unless supported.include?(listener_strategy) if transport != :native && fork_mode == :grpc_fork_support raise ConfigurationError, "grpc_fork_support requires transport :native" end unless metrics_backend == :pipe || (metrics_backend == :otlp && metrics_recorder_factory) raise ConfigurationError, "metrics_backend requires an installed recorder (:pipe is built in)" end raise ConfigurationError, "This release supports phased_restart_surge 1" unless phased_restart_surge == 1 unless worker_recycle.empty? raise ConfigurationError, "worker_recycle requires workers > 0" unless workers.positive? if bind.end_with?(":0") && listener_strategy != :inherited_fd raise ConfigurationError, "worker_recycle requires a fixed bind port" end end raise ConfigurationError, "grpc_fork_support requires workers > 0" if workers.zero? && fork_mode != :clean raise ConfigurationError, "at least one controller must be registered" if controllers.empty? self end |
#validate_single_process! ⇒ Object
142 143 144 145 146 147 |
# File '/home/runner/work/gritz/gritz/sources/gritz-core/lib/gritz/configuration.rb', line 142 def validate_single_process! validate_runtime! raise ConfigurationError, "Testing::Server requires workers 0; use Testing::Cluster for supervised servers" unless workers.zero? self end |