Class: CircuitBreaker::CircuitHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/circuit_breaker/circuit_handler.rb

Overview

CircuitHandler is stateless, so the circuit_state gets mixed in with the calling object.

Constant Summary collapse

DEFAULT_FAILURE_THRESHOLD =
5
DEFAULT_FAILURE_TIMEOUT =
5

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger = nil) ⇒ CircuitHandler

Returns a new instance of CircuitHandler.



27
28
29
30
31
# File 'lib/circuit_breaker/circuit_handler.rb', line 27

def initialize(logger = nil)
  @logger = logger
  @failure_threshold = DEFAULT_FAILURE_THRESHOLD
  @failure_timeout = DEFAULT_FAILURE_TIMEOUT
end

Instance Attribute Details

#failure_thresholdObject

The number of failures needed to trip the breaker.



12
13
14
# File 'lib/circuit_breaker/circuit_handler.rb', line 12

def failure_threshold
  @failure_threshold
end

#failure_timeoutObject

The period of time in seconds before attempting to reset the breaker.



17
18
19
# File 'lib/circuit_breaker/circuit_handler.rb', line 17

def failure_timeout
  @failure_timeout
end

#loggerObject

Optional logger.



22
23
24
# File 'lib/circuit_breaker/circuit_handler.rb', line 22

def logger
  @logger
end

Instance Method Details

#handle(circuit_state, method, *args) ⇒ Object

Handles the method covered by the circuit breaker.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/circuit_breaker/circuit_handler.rb', line 43

def handle(circuit_state, method, *args)
  if is_tripped(circuit_state)
    @logger.debug("handle: breaker is tripped, refusing to execute: #{circuit_state.inspect}") if @logger
    on_circuit_open(circuit_state)
  end

  begin
    out = method[*args]
    on_success(circuit_state)
  rescue Exception
    on_failure(circuit_state)
    raise
  end
  return out
end

#is_failure_threshold_reached(circuit_state) ⇒ Object

Returns true when the number of failures is sufficient to trip the breaker, false otherwise.



62
63
64
65
66
67
# File 'lib/circuit_breaker/circuit_handler.rb', line 62

def is_failure_threshold_reached(circuit_state)
  out = (circuit_state.failure_count > failure_threshold)
  @logger.debug("is_failure_threshold_reached: #{circuit_state.failure_count} > #{failure_threshold} == #{out}") if @logger

  return out
end

#is_timeout_exceeded(circuit_state) ⇒ Object

Returns true if enough time has elapsed since the last failure time, false otherwise.



72
73
74
75
76
77
78
# File 'lib/circuit_breaker/circuit_handler.rb', line 72

def is_timeout_exceeded(circuit_state)
  now = Time.now

  time_since = now - circuit_state.last_failure_time
  @logger.debug("timeout_exceeded: time since last failure = #{time_since.inspect}") if @logger
  return time_since >= failure_timeout
end

#is_tripped(circuit_state) ⇒ Object

Returns true if the circuit breaker is still open and the timeout has not been exceeded, false otherwise.



84
85
86
87
88
89
90
91
92
# File 'lib/circuit_breaker/circuit_handler.rb', line 84

def is_tripped(circuit_state)

  if circuit_state.open? && is_timeout_exceeded(circuit_state)
    @logger.debug("is_tripped: attempting reset into half open state for #{circuit_state.inspect}") if @logger
    circuit_state.attempt_reset
  end

  return circuit_state.open?
end

#new_circuit_stateObject

Returns a new CircuitState instance.



36
37
38
# File 'lib/circuit_breaker/circuit_handler.rb', line 36

def new_circuit_state
  ::CircuitBreaker::CircuitState.new
end

#on_circuit_open(circuit_state) ⇒ Object

Called when a call is made and the circuit is open. Raises a CircuitBrokenException exception.



129
130
131
132
133
# File 'lib/circuit_breaker/circuit_handler.rb', line 129

def on_circuit_open(circuit_state)
  @logger.debug("on_circuit_open: raising for #{circuit_state.inspect}") if @logger
      
  raise CircuitBreaker::CircuitBrokenException.new("Circuit broken, please wait for timeout", circuit_state)
end

#on_failure(circuit_state) ⇒ Object

Called when an individual failure happens.



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/circuit_breaker/circuit_handler.rb', line 114

def on_failure(circuit_state)
  @logger.debug("on_failure: circuit_state = #{circuit_state.inspect}") if @logger
  
  circuit_state.increment_failure_count

  if is_failure_threshold_reached(circuit_state) || circuit_state.half_open?
    # Set us into a closed state.
    @logger.debug("on_failure: tripping circuit breaker #{circuit_state.inspect}") if @logger
    circuit_state.trip
  end
end

#on_success(circuit_state) ⇒ Object

Called when an individual success happens.



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/circuit_breaker/circuit_handler.rb', line 97

def on_success(circuit_state)
  @logger.debug("on_success: #{circuit_state.inspect}") if @logger

  if circuit_state.closed?
    @logger.debug("on_success: reset_failure_count #{circuit_state.inspect}") if @logger
    circuit_state.reset_failure_count
  end

  if circuit_state.half_open?
    @logger.debug("on_success: reset circuit #{circuit_state.inspect}") if @logger
    circuit_state.reset
  end
end