Class: BreakerMachines::DSL::CircuitBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/breaker_machines/dsl/circuit_builder.rb

Overview

DSL builder for configuring circuit breakers with a fluent interface

Direct Known Subclasses

CascadingCircuitBuilder

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCircuitBuilder

Returns a new instance of CircuitBuilder.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 9

def initialize
  @config = {
    failure_threshold: 5,
    failure_window: 60.seconds,
    success_threshold: 1,
    timeout: nil,
    reset_timeout: 60.seconds,
    half_open_calls: 1,
    exceptions: [StandardError],
    storage: nil,
    metrics: nil,
    fallback: nil,
    on_open: nil,
    on_close: nil,
    on_half_open: nil,
    on_reject: nil,
    notifications: [],
    fiber_safe: BreakerMachines.config.fiber_safe
  }
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



7
8
9
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 7

def config
  @config
end

Instance Method Details

#backends(*backend_list) ⇒ Object

Configure multiple backends



140
141
142
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 140

def backends(*backend_list)
  @config[:backends] = backend_list.flatten
end

#fallback(value = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 99

def fallback(value = nil, &block)
  raise ArgumentError, 'Fallback requires either a value or a block' if value.nil? && !block_given?

  fallback_value = block || value

  if @config[:fallback].is_a?(Array)
    @config[:fallback] << fallback_value
  elsif @config[:fallback]
    @config[:fallback] = [@config[:fallback], fallback_value]
  else
    @config[:fallback] = fallback_value
  end
end

#fiber_safe(enabled = true) ⇒ Object

rubocop:disable Style/OptionalBooleanParameter



163
164
165
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 163

def fiber_safe(enabled = true) # rubocop:disable Style/OptionalBooleanParameter
  @config[:fiber_safe] = enabled
end

#half_open_requests(count) ⇒ Object



70
71
72
73
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 70

def half_open_requests(count)
  validate_positive_integer!(:half_open_requests, count)
  @config[:half_open_calls] = count
end

#handle(*exceptions) ⇒ Object



159
160
161
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 159

def handle(*exceptions)
  @config[:exceptions] = exceptions
end

#hedgedObject

Configure hedged requests



130
131
132
133
134
135
136
137
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 130

def hedged(&)
  if block_given?
    hedged_builder = DSL::HedgedBuilder.new(@config)
    hedged_builder.instance_eval(&)
  else
    @config[:hedged_requests] = true
  end
end

#max_concurrent(limit) ⇒ Object



167
168
169
170
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 167

def max_concurrent(limit)
  validate_positive_integer!(:max_concurrent, limit)
  @config[:max_concurrent] = limit
end

#metrics(recorder = nil, &block) ⇒ Object



95
96
97
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 95

def metrics(recorder = nil, &block)
  @config[:metrics] = recorder || block
end

#notify(service, url = nil, events: %i[open close],, **options) ⇒ Object



149
150
151
152
153
154
155
156
157
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 149

def notify(service, url = nil, events: i[open close], **options)
  notification = {
    via: service,
    url: url,
    events: Array(events),
    options: options
  }
  @config[:notifications] << notification
end

#on_close(&block) ⇒ Object



117
118
119
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 117

def on_close(&block)
  @config[:on_close] = block
end

#on_half_open(&block) ⇒ Object



121
122
123
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 121

def on_half_open(&block)
  @config[:on_half_open] = block
end

#on_open(&block) ⇒ Object



113
114
115
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 113

def on_open(&block)
  @config[:on_open] = block
end

#on_reject(&block) ⇒ Object



125
126
127
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 125

def on_reject(&block)
  @config[:on_reject] = block
end

#parallel_calls(count, timeout: nil) ⇒ Object

Advanced features



173
174
175
176
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 173

def parallel_calls(count, timeout: nil)
  @config[:parallel_calls] = count
  @config[:parallel_timeout] = timeout
end

#parallel_fallback(fallback_list) ⇒ Object

Configure parallel fallback execution



145
146
147
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 145

def parallel_fallback(fallback_list)
  @config[:fallback] = DSL::ParallelFallbackWrapper.new(fallback_list)
end

#reset_after(duration, jitter: nil) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 55

def reset_after(duration, jitter: nil)
  validate_positive_integer!(:duration, duration.to_i)
  @config[:reset_timeout] = duration.to_i

  return unless jitter

  validate_jitter!(jitter)
  @config[:reset_timeout_jitter] = jitter
end

#storage(backend, **options) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 75

def storage(backend, **options)
  @config[:storage] = case backend
                      when :memory
                        Storage::Memory.new(**options)
                      when :bucket_memory
                        Storage::BucketMemory.new(**options)
                      when :cache
                        Storage::Cache.new(**options)
                      when :null
                        Storage::Null.new(**options)
                      when :fallback_chain
                        config = options.is_a?(Proc) ? options.call(timeout: 5) : options
                        Storage::FallbackChain.new(config)
                      when Class
                        backend.new(**options)
                      else
                        backend
                      end
end

#threshold(failures: nil, failure_rate: nil, minimum_calls: nil, within: 60.seconds, successes: nil) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 30

def threshold(failures: nil, failure_rate: nil, minimum_calls: nil, within: 60.seconds, successes: nil)
  if failure_rate
    # Rate-based threshold
    validate_failure_rate!(failure_rate)
    validate_positive_integer!(:minimum_calls, minimum_calls) if minimum_calls

    @config[:failure_rate] = failure_rate
    @config[:minimum_calls] = minimum_calls || 5
    @config[:use_rate_threshold] = true
  elsif failures
    # Absolute count threshold (existing behavior)
    validate_positive_integer!(:failures, failures)
    @config[:failure_threshold] = failures
    @config[:use_rate_threshold] = false
  end

  validate_positive_integer!(:within, within.to_i)
  @config[:failure_window] = within.to_i

  return unless successes

  validate_positive_integer!(:successes, successes)
  @config[:success_threshold] = successes
end

#timeout(duration) ⇒ Object



65
66
67
68
# File 'lib/breaker_machines/dsl/circuit_builder.rb', line 65

def timeout(duration)
  validate_non_negative_integer!(:timeout, duration.to_i)
  @config[:timeout] = duration.to_i
end