module SwitchGear::CircuitBreaker

Public Instance Methods

add_failure(failure) click to toggle source

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

# File lib/switch_gear/circuit_breaker.rb, line 57
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, SwitchGear::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/switch_gear/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/switch_gear/circuit_breaker.rb, line 35
def closed?
  state == :closed
end
failure_count() click to toggle source

@return [Integer] The count of current failures

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

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

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

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

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

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

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

@return most recent failure [SwitchGear::CircuitBreaker::Failure]

# File lib/switch_gear/circuit_breaker.rb, line 20
def most_recent_failure
  failures.last
end
open?() click to toggle source

@return [Boolean] Whether the circuit is open

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

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

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

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

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

Private Instance Methods

check_reset_timeout() click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 85
def check_reset_timeout
  return if !open?
  if failure_count == 0 || reset_period_lapsed?
    self.state = :half_open
  end
end
do_run(args) { |*args| ... } click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 78
def do_run(args)
  yield *args
  reset_failures
rescue => e
  handle_failure(e)
end
handle_failure(e) click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 102
def handle_failure(e)
  failure = Failure.new(e)
  add_failure(failure)
  logger.warn failure.to_s
  if half_open? || failure_count >= failure_limit
    self.state = :open
  else
    self.state = :closed
  end
end
must_implement(arg) click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 74
def must_implement(arg)
  raise NotImplementedError.new("You must implement #{arg}.")
end
reset_failures() click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 96
def reset_failures
  self.failures = []
  self.state = :closed
  logger.info "Circuit closed"
end
reset_period_lapsed?() click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 92
def reset_period_lapsed?
  (Time.now.utc - most_recent_failure.timestamp) > reset_timeout
end
run_validations() click to toggle source
# File lib/switch_gear/circuit_breaker.rb, line 113
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