Class: Woods::Resilience::CircuitBreaker
- Inherits:
-
Object
- Object
- Woods::Resilience::CircuitBreaker
- Defined in:
- lib/woods/resilience/circuit_breaker.rb
Overview
Circuit breaker pattern for protecting external service calls.
Tracks failures and transitions between three states:
- :closed — normal operation, calls pass through
- :open — too many failures, calls are rejected immediately
- :half_open — testing recovery, one call is allowed through
Instance Attribute Summary collapse
-
#state ⇒ Symbol
readonly
Current state — :closed, :open, or :half_open.
Instance Method Summary collapse
-
#call { ... } ⇒ Object
Execute a block through the circuit breaker.
-
#initialize(threshold: 5, reset_timeout: 60, success_threshold: 1) ⇒ CircuitBreaker
constructor
A new instance of CircuitBreaker.
Constructor Details
#initialize(threshold: 5, reset_timeout: 60, success_threshold: 1) ⇒ CircuitBreaker
Returns a new instance of CircuitBreaker.
42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/woods/resilience/circuit_breaker.rb', line 42 def initialize(threshold: 5, reset_timeout: 60, success_threshold: 1) @threshold = threshold @reset_timeout = reset_timeout @success_threshold = success_threshold @state = :closed @failure_count = 0 @success_count = 0 @last_failure_time = nil @half_open_probe_in_flight = false @mutex = Mutex.new end |
Instance Attribute Details
#state ⇒ Symbol (readonly)
Returns Current state — :closed, :open, or :half_open.
35 36 37 |
# File 'lib/woods/resilience/circuit_breaker.rb', line 35 def state @state end |
Instance Method Details
#call { ... } ⇒ Object
Execute a block through the circuit breaker.
In half_open, only a SINGLE probe is admitted at a time: concurrent calls are rejected with Woods::Resilience::CircuitOpenError until the probe resolves. This prevents a thundering herd of probes against a still-recovering service, and — because probes can't overlap — removes the race where a slow probe's success would wipe failures recorded by a concurrent one.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/woods/resilience/circuit_breaker.rb', line 66 def call(&block) probing = admit_call! begin result = block.call rescue CircuitOpenError # A nested breaker tripped — release our probe slot but don't count # it as this breaker's own failure. @mutex.synchronize { @half_open_probe_in_flight = false if probing } raise rescue StandardError => e @mutex.synchronize do @half_open_probe_in_flight = false if probing record_failure(probing) end raise e end @mutex.synchronize do @half_open_probe_in_flight = false if probing record_success(probing) end result end |