Class: BreakerMachines::CircuitGroup

Inherits:
Object
  • Object
show all
Includes:
DSL
Defined in:
lib/breaker_machines/circuit_group.rb

Overview

CircuitGroup provides coordinated management of multiple related circuits with support for dependencies, shared configuration, and group-wide operations

Defined Under Namespace

Classes: DependencyWrapper

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from DSL

#apply_template, #circuit_instances, #circuits_report, #circuits_summary, #cleanup_stale_dynamic_circuits, #dynamic_circuit, #dynamic_circuit_names, included, #remove_dynamic_circuit, #reset_all_circuits

Constructor Details

#initialize(name, config = {}) ⇒ CircuitGroup



11
12
13
14
15
16
17
# File 'lib/breaker_machines/circuit_group.rb', line 11

def initialize(name, config = {})
  @name = name
  @config = config
  @circuits = {}
  @dependencies = {}
  @async_mode = config[:async_mode] || false
end

Instance Attribute Details

#circuitsObject (readonly)

Returns the value of attribute circuits.



9
10
11
# File 'lib/breaker_machines/circuit_group.rb', line 9

def circuits
  @circuits
end

#configObject (readonly)

Returns the value of attribute config.



9
10
11
# File 'lib/breaker_machines/circuit_group.rb', line 9

def config
  @config
end

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



9
10
11
# File 'lib/breaker_machines/circuit_group.rb', line 9

def dependencies
  @dependencies
end

#nameObject (readonly)

Returns the value of attribute name.



9
10
11
# File 'lib/breaker_machines/circuit_group.rb', line 9

def name
  @name
end

Instance Method Details

#[](name) ⇒ Object

Get a circuit by name



67
68
69
# File 'lib/breaker_machines/circuit_group.rb', line 67

def [](name)
  @circuits[name]
end

#all_healthy?Boolean

Check if all circuits in the group are healthy



72
73
74
# File 'lib/breaker_machines/circuit_group.rb', line 72

def all_healthy?
  @circuits.values.all? { |circuit| circuit.closed? || circuit.half_open? }
end

#any_open?Boolean

Check if any circuit in the group is open



77
78
79
# File 'lib/breaker_machines/circuit_group.rb', line 77

def any_open?
  @circuits.values.any?(&:open?)
end

#circuit(name, options = {}) ⇒ Object

Define a circuit within this group with optional dependencies

Options Hash (options):

  • :depends_on (Symbol, Array<Symbol>)

    Other circuits this one depends on

  • :guard_with (Proc)

    Additional guard conditions



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/breaker_machines/circuit_group.rb', line 24

def circuit(name, options = {}, &)
  depends_on = Array(options.delete(:depends_on))
  guard_proc = options.delete(:guard_with)

  # Add group-wide defaults
  circuit_config = @config.merge(options)

  # Create appropriate circuit type
  circuit_class = if options[:cascades_to] || depends_on.any?
                    BreakerMachines::CascadingCircuit
                  elsif @async_mode
                    BreakerMachines::AsyncCircuit
                  else
                    BreakerMachines::Circuit
                  end

  # Build the circuit
  circuit_instance = if block_given?
                       builder = BreakerMachines::DSL::CircuitBuilder.new
                       builder.instance_eval(&)
                       built_config = builder.config.merge(circuit_config)
                       circuit_class.new(full_circuit_name(name), built_config)
                     else
                       circuit_class.new(full_circuit_name(name), circuit_config)
                     end

  # Store dependencies and guards
  if depends_on.any? || guard_proc
    @dependencies[name] = {
      depends_on: depends_on,
      guard: guard_proc
    }

    # Wrap the circuit with dependency checking
    circuit_instance = DependencyWrapper.new(circuit_instance, self, name)
  end

  @circuits[name] = circuit_instance
  BreakerMachines.register(circuit_instance)
  circuit_instance
end

#dependencies_met?(circuit_name) ⇒ Boolean

Check dependencies for a specific circuit



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/breaker_machines/circuit_group.rb', line 97

def dependencies_met?(circuit_name)
  deps = @dependencies[circuit_name]
  return true unless deps

  depends_on = deps[:depends_on]
  guard = deps[:guard]

  # Check circuit dependencies recursively
  dependencies_healthy = depends_on.all? do |dep_name|
    dep_circuit = @circuits[dep_name]
    # Circuit must exist, be healthy, AND have its own dependencies met
    dep_circuit && (dep_circuit.closed? || dep_circuit.half_open?) && dependencies_met?(dep_name)
  end

  # Check custom guard
  guard_passed = guard ? guard.call : true

  dependencies_healthy && guard_passed
end

#reset_all!Object

Reset all circuits in the group



87
88
89
# File 'lib/breaker_machines/circuit_group.rb', line 87

def reset_all!
  @circuits.each_value(&:reset!)
end

#statusObject

Get status of all circuits



82
83
84
# File 'lib/breaker_machines/circuit_group.rb', line 82

def status
  @circuits.transform_values(&:status_name)
end

#trip_all!Object

Force open all circuits



92
93
94
# File 'lib/breaker_machines/circuit_group.rb', line 92

def trip_all!
  @circuits.each_value(&:force_open!)
end