Class: Hungrytable::CircuitBreaker
- Inherits:
-
Object
- Object
- Hungrytable::CircuitBreaker
- Defined in:
- lib/hungrytable/circuit_breaker.rb
Overview
Circuit Breaker pattern to prevent cascading failures when API is down
States:
- CLOSED: Normal operation, requests pass through
- OPEN: Too many failures, requests fail immediately
- HALF_OPEN: Testing if service recovered
Usage:
Hungrytable::CircuitBreaker.call do
# Make API request
end
Defined Under Namespace
Classes: CircuitOpenError
Instance Attribute Summary collapse
-
#failure_count ⇒ Object
readonly
Returns the value of attribute failure_count.
-
#last_failure_time ⇒ Object
readonly
Returns the value of attribute last_failure_time.
-
#state ⇒ Object
readonly
Returns the value of attribute state.
-
#success_count ⇒ Object
readonly
Returns the value of attribute success_count.
Class Method Summary collapse
-
.call { ... } ⇒ Object
Execute a block with circuit breaker protection.
-
.configure(failure_threshold: 5, timeout: 60, success_threshold: 2) ⇒ Object
Configure circuit breaker.
-
.open? ⇒ Boolean
Check if circuit is open.
-
.reset! ⇒ Object
Reset the circuit breaker.
-
.state ⇒ Symbol
Get current state.
-
.stats ⇒ Hash
Get circuit breaker statistics.
Instance Method Summary collapse
- #call ⇒ Object
- #configure(failure_threshold: nil, timeout: nil, success_threshold: nil) ⇒ Object
-
#initialize ⇒ CircuitBreaker
constructor
A new instance of CircuitBreaker.
- #open? ⇒ Boolean
- #reset! ⇒ Object
- #stats ⇒ Object
Constructor Details
#initialize ⇒ CircuitBreaker
Returns a new instance of CircuitBreaker.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/hungrytable/circuit_breaker.rb', line 75 def initialize @state = :closed @failure_count = 0 @success_count = 0 @last_failure_time = nil @mutex = Mutex.new # Default configuration @config = { failure_threshold: 5, # Open after 5 failures timeout: 60, # Try again after 60 seconds success_threshold: 2 # Close after 2 successes in half-open } end |
Instance Attribute Details
#failure_count ⇒ Object (readonly)
Returns the value of attribute failure_count.
73 74 75 |
# File 'lib/hungrytable/circuit_breaker.rb', line 73 def failure_count @failure_count end |
#last_failure_time ⇒ Object (readonly)
Returns the value of attribute last_failure_time.
73 74 75 |
# File 'lib/hungrytable/circuit_breaker.rb', line 73 def last_failure_time @last_failure_time end |
#state ⇒ Object (readonly)
Returns the value of attribute state.
73 74 75 |
# File 'lib/hungrytable/circuit_breaker.rb', line 73 def state @state end |
#success_count ⇒ Object (readonly)
Returns the value of attribute success_count.
73 74 75 |
# File 'lib/hungrytable/circuit_breaker.rb', line 73 def success_count @success_count end |
Class Method Details
.call { ... } ⇒ Object
Execute a block with circuit breaker protection
27 28 29 |
# File 'lib/hungrytable/circuit_breaker.rb', line 27 def call(&block) instance.call(&block) end |
.configure(failure_threshold: 5, timeout: 60, success_threshold: 2) ⇒ Object
Configure circuit breaker
58 59 60 61 62 63 64 |
# File 'lib/hungrytable/circuit_breaker.rb', line 58 def configure(failure_threshold: 5, timeout: 60, success_threshold: 2) instance.configure( failure_threshold: failure_threshold, timeout: timeout, success_threshold: success_threshold ) end |
.open? ⇒ Boolean
Check if circuit is open
33 34 35 |
# File 'lib/hungrytable/circuit_breaker.rb', line 33 def open? instance.open? end |
.reset! ⇒ Object
Reset the circuit breaker
50 51 52 |
# File 'lib/hungrytable/circuit_breaker.rb', line 50 def reset! instance.reset! end |
.state ⇒ Symbol
Get current state
39 40 41 |
# File 'lib/hungrytable/circuit_breaker.rb', line 39 def state instance.state end |
.stats ⇒ Hash
Get circuit breaker statistics
45 46 47 |
# File 'lib/hungrytable/circuit_breaker.rb', line 45 def stats instance.stats end |
Instance Method Details
#call ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/hungrytable/circuit_breaker.rb', line 98 def call @mutex.synchronize do check_state_transition if @state == :open raise CircuitOpenError end end begin result = yield record_success result rescue UnauthorizedError, ServerError, HTTPError => e record_failure raise e end end |
#configure(failure_threshold: nil, timeout: nil, success_threshold: nil) ⇒ Object
90 91 92 93 94 95 96 |
# File 'lib/hungrytable/circuit_breaker.rb', line 90 def configure(failure_threshold: nil, timeout: nil, success_threshold: nil) @mutex.synchronize do @config[:failure_threshold] = failure_threshold if failure_threshold @config[:timeout] = timeout if timeout @config[:success_threshold] = success_threshold if success_threshold end end |
#open? ⇒ Boolean
117 118 119 |
# File 'lib/hungrytable/circuit_breaker.rb', line 117 def open? @state == :open end |
#reset! ⇒ Object
131 132 133 134 135 136 137 138 |
# File 'lib/hungrytable/circuit_breaker.rb', line 131 def reset! @mutex.synchronize do @state = :closed @failure_count = 0 @success_count = 0 @last_failure_time = nil end end |
#stats ⇒ Object
121 122 123 124 125 126 127 128 129 |
# File 'lib/hungrytable/circuit_breaker.rb', line 121 def stats { state: @state, failure_count: @failure_count, success_count: @success_count, last_failure_time: @last_failure_time, config: @config } end |