Module: BreakerMachines::DSL
- Extended by:
- ActiveSupport::Concern
- Included in:
- CircuitGroup
- Defined in:
- lib/breaker_machines/dsl.rb,
lib/breaker_machines/dsl/hedged_builder.rb,
lib/breaker_machines/dsl/circuit_builder.rb,
lib/breaker_machines/dsl/cascading_circuit_builder.rb,
lib/breaker_machines/dsl/parallel_fallback_wrapper.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: CascadingCircuitBuilder, 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
156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/breaker_machines/dsl.rb', line 156 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
215 216 217 218 219 220 221 |
# File 'lib/breaker_machines/dsl.rb', line 215 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
169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/breaker_machines/dsl.rb', line 169 def circuit(name) self.class.circuits[name] ||= {} @circuit_instances ||= {} config = self.class.circuits[name].merge(owner: self) circuit_type = config.delete(:circuit_type) @circuit_instances[name] ||= case circuit_type when :cascading CascadingCircuit.new(name, config) else Circuit.new(name, config) end end |
#circuit_instances ⇒ Object
Get all circuit instances for this object
249 250 251 |
# File 'lib/breaker_machines/dsl.rb', line 249 def circuit_instances @circuit_instances || {} end |
#circuits_report ⇒ Object
Get detailed information for all circuits
259 260 261 |
# File 'lib/breaker_machines/dsl.rb', line 259 def circuits_report circuit_instances.transform_values(&:to_h) end |
#circuits_summary ⇒ Object
Get summary of all circuits for this instance
254 255 256 |
# File 'lib/breaker_machines/dsl.rb', line 254 def circuits_summary circuit_instances.transform_values(&:summary) end |
#cleanup_stale_dynamic_circuits(max_age_seconds = 3600) ⇒ Object
Cleanup stale dynamic circuits (global)
279 280 281 |
# File 'lib/breaker_machines/dsl.rb', line 279 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)
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/breaker_machines/dsl.rb', line 188 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 = DSL::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
274 275 276 |
# File 'lib/breaker_machines/dsl.rb', line 274 def dynamic_circuit_names BreakerMachines.registry.dynamic_circuit_names end |
#remove_dynamic_circuit(name) ⇒ Object
Remove a global dynamic circuit by name
269 270 271 |
# File 'lib/breaker_machines/dsl.rb', line 269 def remove_dynamic_circuit(name) BreakerMachines.registry.remove_dynamic_circuit(name) end |
#reset_all_circuits ⇒ Object
Reset all circuits for this instance
264 265 266 |
# File 'lib/breaker_machines/dsl.rb', line 264 def reset_all_circuits circuit_instances.each_value(&:hard_reset!) end |