class Rester::Utils::CircuitBreaker
Attributes
block[R]
failure_count[R]
last_failed_at[R]
retry_period[R]
threshold[R]
Public Class Methods
new(opts={}, &block)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 14 def initialize(opts={}, &block) @_synchronizer = Mutex.new @_retry_lock = Mutex.new self.threshold = opts[:threshold] self.retry_period = opts[:retry_period] @block = block reset end
Public Instance Methods
call(*args)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 52 def call(*args) if closed? _call(*args) elsif half_open? && @_retry_lock.try_lock # Ensure only one thread can retry. begin _call(*args) ensure @_retry_lock.unlock end else fail CircuitOpenError end end
closed?()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 31 def closed? !reached_threshold? end
half_open?()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 35 def half_open? !closed? && retry_period_passed? end
on_close(&block)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 27 def on_close(&block) _callbacks[:close] = block end
on_open(&block)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 23 def on_open(&block) _callbacks[:open] = block end
open?()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 39 def open? !closed? && !half_open? end
reached_threshold?()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 43 def reached_threshold? failure_count >= threshold end
reset()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 67 def reset _synchronize do @failure_count = 0 @last_failed_at = nil end end
retry_period_passed?()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 47 def retry_period_passed? lf_at = last_failed_at !lf_at || (Time.now - lf_at) > retry_period end
Protected Instance Methods
retry_period=(retry_period)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 82 def retry_period=(retry_period) unless (@retry_period = (retry_period || 1).to_f) > 0 fail ArgumentError, 'retry_period must be > 0' end end
threshold=(threshold)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 76 def threshold=(threshold) unless (@threshold = (threshold || 3).to_i) > 0 fail ArgumentError, 'threshold must be > 0' end end
Private Instance Methods
_call(*args)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 90 def _call(*args) begin block.call(*args).tap { _record_success } rescue _record_failure raise end end
_call_on(type)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 103 def _call_on(type) (cb = _callbacks[type]) && cb.call end
_callbacks()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 99 def _callbacks @__callbacks ||= {} end
_record_failure()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 121 def _record_failure if @failure_count < threshold _synchronize do if @failure_count < threshold @failure_count += 1 # If the threshold has now been reached, we're opening the circuit. _call_on(:open) if @failure_count == threshold end end end @last_failed_at = Time.now end
_record_success()
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 111 def _record_success if @failure_count > 0 _synchronize do # If the threshold had been reached, we're now closing the circuit. _call_on(:close) if @failure_count == threshold @failure_count = 0 end end end
_synchronize(&block)
click to toggle source
# File lib/rester/utils/circuit_breaker.rb, line 107 def _synchronize(&block) @_synchronizer.synchronize(&block) end