Module: BreakerMachines::DSL
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/breaker_machines/dsl.rb
Overview
DSL module for adding circuit breakers to classes
This module uses WeakRef to track instances that include the DSL. Why? In long-running applications (web servers, background workers), objects that include this DSL may be created and destroyed frequently. Without WeakRef, the registry would hold strong references to these objects, preventing garbage collection and causing memory leaks.
Example scenario: A Rails controller that includes BreakerMachines::DSL is instantiated for each request. Without WeakRef, every controller instance would be kept in memory forever.
Defined Under Namespace
Classes: CircuitBuilder, HedgedBuilder, ParallelFallbackWrapper
Class Method Summary collapse
-
.included(base) ⇒ Object
Use included callback to add instance tracking.
Instance Method Summary collapse
-
#apply_template(circuit_name, template_name) ⇒ Object
Apply a template to an existing or new circuit.
- #circuit(name) ⇒ Object
-
#circuit_instances ⇒ Object
Get all circuit instances for this object.
-
#circuits_report ⇒ Object
Get detailed information for all circuits.
-
#circuits_summary ⇒ Object
Get summary of all circuits for this instance.
-
#cleanup_stale_dynamic_circuits(max_age_seconds = 3600) ⇒ Object
Cleanup stale dynamic circuits (global).
-
#dynamic_circuit(name, template: nil, global: false, &config_block) ⇒ Object
Create a dynamic circuit breaker with inline configuration Options: global: true - Store circuit globally, preventing memory leaks in long-lived objects global: false - Store circuit locally in this instance (default, backward compatible).
-
#dynamic_circuit_names ⇒ Object
Get all dynamic circuit names from global registry.
-
#remove_dynamic_circuit(name) ⇒ Object
Remove a global dynamic circuit by name.
-
#reset_all_circuits ⇒ Object
Reset all circuits for this instance.
Class Method Details
.included(base) ⇒ Object
Use included callback to add instance tracking
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/breaker_machines/dsl.rb', line 143 def self.included(base) super # Hook into new to register instances base.singleton_class.prepend(Module.new do def new(...) instance = super instance_registry << WeakRef.new(instance) instance end end) end |
Instance Method Details
#apply_template(circuit_name, template_name) ⇒ Object
Apply a template to an existing or new circuit
193 194 195 196 197 198 199 |
# File 'lib/breaker_machines/dsl.rb', line 193 def apply_template(circuit_name, template_name) template_config = self.class.circuit_templates[template_name] raise ArgumentError, "Template '#{template_name}' not found" unless template_config @circuit_instances ||= {} @circuit_instances[circuit_name] = Circuit.new(circuit_name, template_config.merge(owner: self)) end |
#circuit(name) ⇒ Object
156 157 158 159 160 |
# File 'lib/breaker_machines/dsl.rb', line 156 def circuit(name) self.class.circuits[name] ||= {} @circuit_instances ||= {} @circuit_instances[name] ||= Circuit.new(name, self.class.circuits[name].merge(owner: self)) end |
#circuit_instances ⇒ Object
Get all circuit instances for this object
227 228 229 |
# File 'lib/breaker_machines/dsl.rb', line 227 def circuit_instances @circuit_instances || {} end |
#circuits_report ⇒ Object
Get detailed information for all circuits
237 238 239 |
# File 'lib/breaker_machines/dsl.rb', line 237 def circuits_report circuit_instances.transform_values(&:to_h) end |
#circuits_summary ⇒ Object
Get summary of all circuits for this instance
232 233 234 |
# File 'lib/breaker_machines/dsl.rb', line 232 def circuits_summary circuit_instances.transform_values(&:summary) end |
#cleanup_stale_dynamic_circuits(max_age_seconds = 3600) ⇒ Object
Cleanup stale dynamic circuits (global)
257 258 259 |
# File 'lib/breaker_machines/dsl.rb', line 257 def cleanup_stale_dynamic_circuits(max_age_seconds = 3600) BreakerMachines.registry.cleanup_stale_dynamic_circuits(max_age_seconds) end |
#dynamic_circuit(name, template: nil, global: false, &config_block) ⇒ Object
Create a dynamic circuit breaker with inline configuration Options:
global: true - Store circuit globally, preventing memory leaks in long-lived objects
global: false - Store circuit locally in this instance (default, backward compatible)
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/breaker_machines/dsl.rb', line 166 def dynamic_circuit(name, template: nil, global: false, &config_block) # Start with template config if provided base_config = if template && self.class.circuit_templates[template] self.class.circuit_templates[template].deep_dup else default_circuit_config end # Apply additional configuration if block provided if config_block builder = CircuitBuilder.new builder.instance_variable_set(:@config, base_config.deep_dup) builder.instance_eval(&config_block) base_config = builder.config end if global # Use global registry to prevent memory leaks BreakerMachines.registry.get_or_create_dynamic_circuit(name, self, base_config) else # Local storage (backward compatible) @circuit_instances ||= {} @circuit_instances[name] ||= Circuit.new(name, base_config.merge(owner: self)) end end |
#dynamic_circuit_names ⇒ Object
Get all dynamic circuit names from global registry
252 253 254 |
# File 'lib/breaker_machines/dsl.rb', line 252 def dynamic_circuit_names BreakerMachines.registry.dynamic_circuit_names end |
#remove_dynamic_circuit(name) ⇒ Object
Remove a global dynamic circuit by name
247 248 249 |
# File 'lib/breaker_machines/dsl.rb', line 247 def remove_dynamic_circuit(name) BreakerMachines.registry.remove_dynamic_circuit(name) end |
#reset_all_circuits ⇒ Object
Reset all circuits for this instance
242 243 244 |
# File 'lib/breaker_machines/dsl.rb', line 242 def reset_all_circuits circuit_instances.each_value(&:reset) end |