module CircuitBreaker

Constants

VERSION

Public Instance Methods

add_failure(failure) click to toggle source

@param failure [CircuitBreaker::Failure] a list of failures @return [void]

# File lib/circuit_breaker.rb, line 52
def add_failure(failure)
  must_implement(:add_failure)
end
call(*args) click to toggle source

Calls the circuit proc/lambda if the circuit is closed or half-open

@param args [Array<Object>] Any number of Objects to be called with the circuit block. @return [Void, CircuitBreaker::Open] No usable return value if successful, but will raise an error if failure_limit is reached or if the circuit is open

# File lib/circuit_breaker.rb, line 13
def call(*args)
  check_reset_timeout
  raise OpenError if open?
  do_run(args, &circuit)
end
closed?() click to toggle source

@return [Boolean] Whether the circuit is closed

# File lib/circuit_breaker.rb, line 30
def closed?
  state == :closed
end
failure_count() click to toggle source

@return [Integer] The count of current failures

# File lib/circuit_breaker.rb, line 20
def failure_count
  failures.size
end
failures() click to toggle source

@return [Array<CircuitBreaker::Failure>] a list of current failures

# File lib/circuit_breaker.rb, line 40
def failures
  must_implement(:failures)
end
failures=(failure) click to toggle source

@param failure [Array<CircuitBreaker::Failure>] a list of failures @return [void]

# File lib/circuit_breaker.rb, line 46
def failures=(failure)
  must_implement(:failures=)
end
half_open?() click to toggle source

@return [Boolean] Whether the circuit is half-open

# File lib/circuit_breaker.rb, line 35
def half_open?
  state == :half_open
end
open?() click to toggle source

@return [Boolean] Whether the circuit is open

# File lib/circuit_breaker.rb, line 25
def open?
  state == :open
end
state() click to toggle source

@return [Symbol] - either :open, :closed, :half-open

# File lib/circuit_breaker.rb, line 57
def state
  must_implement(:state)
end
state=(state) click to toggle source

@param state [Symbol] - either :open, :closed, :half-open @return [void]

# File lib/circuit_breaker.rb, line 63
def state=(state)
  must_implement(:state=)
end

Private Instance Methods

check_reset_timeout() click to toggle source
# File lib/circuit_breaker.rb, line 80
def check_reset_timeout
  return if !open?
  if reset_period_lapsed?
    self.state = :half_open
  end
end
do_run(args) { |*args| ... } click to toggle source
# File lib/circuit_breaker.rb, line 73
def do_run(args)
  yield *args
  reset_failures
rescue => e
  handle_failure(e)
end
handle_failure(e) click to toggle source
# File lib/circuit_breaker.rb, line 97
def handle_failure(e)
  failure = Failure.new(e)
  add_failure(failure)
  logger.warn failure.to_s
  if half_open? || failures.size >= failure_limit
    self.state = :open
  else
    self.state = :closed
  end
end
must_implement(arg) click to toggle source
# File lib/circuit_breaker.rb, line 69
def must_implement(arg)
  raise NotImplementedError.new("You must implement #{arg}.")
end
reset_failures() click to toggle source
# File lib/circuit_breaker.rb, line 91
def reset_failures
  self.failures = []
  self.state = :closed
  logger.info "Circuit closed"
end
reset_period_lapsed?() click to toggle source
# File lib/circuit_breaker.rb, line 87
def reset_period_lapsed?
  (Time.now.utc - failures.last.timestamp) > reset_timeout
end
run_validations() click to toggle source
# File lib/circuit_breaker.rb, line 108
def run_validations
  logger_methods = [:debug, :info, :warn, :error]
  if !logger_methods.all? { |e| logger.respond_to?(e) }
    raise NotImplementedError.new("Your logger must respond to #{logger_methods}")
  end
  if !circuit.respond_to?(:call)
    raise NotImplementedError.new("Your circuit must respond to #call")
  end
end