Class: Philiprehberger::RetryKit::CircuitBreaker

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

Overview

A simple circuit breaker that tracks failures and opens the circuit when a threshold is exceeded, preventing further calls until a cooldown period has elapsed.

Defined Under Namespace

Classes: OpenError

Constant Summary collapse

STATES =
%i[closed open half_open].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(failure_threshold: 5, cooldown: 30, on_state_change: nil) ⇒ CircuitBreaker

Returns a new instance of CircuitBreaker.

Parameters:

  • failure_threshold (Integer) (defaults to: 5)

    number of failures before opening

  • cooldown (Numeric) (defaults to: 30)

    seconds to wait before transitioning to half-open

  • on_state_change (Proc, nil) (defaults to: nil)

    callback when state changes, receives (old_state, new_state)



19
20
21
22
23
24
25
26
27
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 19

def initialize(failure_threshold: 5, cooldown: 30, on_state_change: nil)
  @failure_threshold = failure_threshold
  @cooldown = cooldown
  @on_state_change = on_state_change
  @failure_count = 0
  @state = :closed
  @last_failure_time = nil
  @mutex = Mutex.new
end

Instance Attribute Details

#cooldownObject (readonly)

Returns the value of attribute cooldown.



14
15
16
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 14

def cooldown
  @cooldown
end

#failure_countObject (readonly)

Returns the value of attribute failure_count.



14
15
16
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 14

def failure_count
  @failure_count
end

#failure_thresholdObject (readonly)

Returns the value of attribute failure_threshold.



14
15
16
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 14

def failure_threshold
  @failure_threshold
end

#stateObject (readonly)

Returns the value of attribute state.



14
15
16
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 14

def state
  @state
end

Instance Method Details

#call { ... } ⇒ Object

Execute a block through the circuit breaker.

Yields:

  • the block to execute

Returns:

  • the block’s return value

Raises:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 34

def call(&block)
  raise ArgumentError, 'Block required' unless block

  @mutex.synchronize { check_state! }

  result = block.call
  record_success
  result
rescue OpenError
  raise
rescue StandardError => e
  record_failure
  raise e
end

#resetObject

Reset the circuit breaker to closed state.



50
51
52
53
54
55
56
# File 'lib/philiprehberger/retry_kit/circuit_breaker.rb', line 50

def reset
  @mutex.synchronize do
    @failure_count = 0
    transition_to(:closed)
    @last_failure_time = nil
  end
end

#trip!self

Force the circuit open, bypassing the failure threshold. Useful for operational controls (e.g. tripping the breaker from an admin panel when upstream is known to be unhealthy).

Returns:

  • (self)


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

def trip!
  @mutex.synchronize do
    @failure_count = @failure_threshold
    @last_failure_time = Time.now
    transition_to(:open)
  end
  self
end