Class: DeadBro::CircuitBreaker

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

Constant Summary collapse

CLOSED =

Circuit breaker states

:closed
OPEN =
:open
HALF_OPEN =
:half_open
DEFAULT_FAILURE_THRESHOLD =

Default configuration

3
DEFAULT_RECOVERY_TIMEOUT =

seconds

60
DEFAULT_RETRY_TIMEOUT =

seconds for retry attempts

300

Instance Method Summary collapse

Constructor Details

#initialize(failure_threshold: DEFAULT_FAILURE_THRESHOLD, recovery_timeout: DEFAULT_RECOVERY_TIMEOUT, retry_timeout: DEFAULT_RETRY_TIMEOUT) ⇒ CircuitBreaker

Returns a new instance of CircuitBreaker.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/dead_bro/circuit_breaker.rb', line 15

def initialize(
  failure_threshold: DEFAULT_FAILURE_THRESHOLD,
  recovery_timeout: DEFAULT_RECOVERY_TIMEOUT,
  retry_timeout: DEFAULT_RETRY_TIMEOUT
)
  @failure_threshold = failure_threshold
  @recovery_timeout = recovery_timeout
  @retry_timeout = retry_timeout

  @state = CLOSED
  @failure_count = 0
  @last_failure_time = nil
  @last_success_time = nil
  @mutex = Mutex.new
end

Instance Method Details

#call(&block) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/dead_bro/circuit_breaker.rb', line 31

def call(&block)
  state = @mutex.synchronize { @state }
  case state
  when CLOSED
    execute_with_monitoring(&block)
  when OPEN
    if should_attempt_reset?
      @mutex.synchronize { @state = HALF_OPEN }
      execute_with_monitoring(&block)
    else
      :circuit_open
    end
  when HALF_OPEN
    execute_with_monitoring(&block)
  end
end

#failure_countObject



52
53
54
# File 'lib/dead_bro/circuit_breaker.rb', line 52

def failure_count
  @mutex.synchronize { @failure_count }
end

#last_failure_timeObject



56
57
58
# File 'lib/dead_bro/circuit_breaker.rb', line 56

def last_failure_time
  @mutex.synchronize { @last_failure_time }
end

#last_success_timeObject



60
61
62
# File 'lib/dead_bro/circuit_breaker.rb', line 60

def last_success_time
  @mutex.synchronize { @last_success_time }
end

#open!Object



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

def open!
  @mutex.synchronize do
    @state = OPEN
    @last_failure_time = Time.now
  end
end

#record_failureObject Also known as: on_failure



101
102
103
104
105
106
107
108
109
# File 'lib/dead_bro/circuit_breaker.rb', line 101

def record_failure
  @mutex.synchronize do
    @failure_count += 1
    @last_failure_time = Time.now
    if @state == HALF_OPEN || @failure_count >= @failure_threshold
      @state = OPEN
    end
  end
end

#record_successObject Also known as: on_success

Public entry points for callers that already know the outcome (e.g. the HTTP dispatcher thread). Preferred over ‘call(&block)` when the caller is doing its own error handling.



93
94
95
96
97
98
99
# File 'lib/dead_bro/circuit_breaker.rb', line 93

def record_success
  @mutex.synchronize do
    @failure_count = 0
    @last_success_time = Time.now
    @state = CLOSED
  end
end

#reset!Object



64
65
66
67
68
69
70
# File 'lib/dead_bro/circuit_breaker.rb', line 64

def reset!
  @mutex.synchronize do
    @state = CLOSED
    @failure_count = 0
    @last_failure_time = nil
  end
end

#should_attempt_reset?Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
# File 'lib/dead_bro/circuit_breaker.rb', line 83

def should_attempt_reset?
  @mutex.synchronize do
    return false unless @last_failure_time
    (Time.now - @last_failure_time) >= @recovery_timeout
  end
end

#stateObject



48
49
50
# File 'lib/dead_bro/circuit_breaker.rb', line 48

def state
  @mutex.synchronize { @state }
end

#transition_to_half_open!Object



79
80
81
# File 'lib/dead_bro/circuit_breaker.rb', line 79

def transition_to_half_open!
  @mutex.synchronize { @state = HALF_OPEN }
end