Class: Resilient::CircuitBreaker

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/resilient/circuit_breaker.rb,
lib/resilient/circuit_breaker/metrics.rb,
lib/resilient/circuit_breaker/registry.rb,
lib/resilient/circuit_breaker/properties.rb,
lib/resilient/circuit_breaker/metrics/bucket.rb,
lib/resilient/circuit_breaker/metrics/bucket_size.rb,
lib/resilient/circuit_breaker/metrics/window_size.rb,
lib/resilient/circuit_breaker/metrics/bucket_range.rb,
lib/resilient/circuit_breaker/metrics/storage/memory.rb

Defined Under Namespace

Classes: Metrics, Properties, Registry

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, properties = nil) ⇒ CircuitBreaker

Private: Builds new instance of a CircuitBreaker.

key - The String or Resilient::Key that determines uniqueness of the
      circuit breaker in the registry and for instrumentation.

properties - The Hash or Resilient::CircuitBreaker::Properties that determine how the
             circuit breaker should behave. Optional. Defaults to new
             Resilient::CircuitBreaker::Properties instance.

Returns CircuitBreaker instance.

Raises:

  • (ArgumentError)


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

def initialize(key, properties = nil)
  raise ArgumentError, "key argument is required" if key.nil?

  @key = Key.wrap(key)
  @properties = Properties.wrap(properties)
  @open = false
  @opened_or_last_checked_at_epoch = 0
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



34
35
36
# File 'lib/resilient/circuit_breaker.rb', line 34

def key
  @key
end

#openObject (readonly)

Returns the value of attribute open.



35
36
37
# File 'lib/resilient/circuit_breaker.rb', line 35

def open
  @open
end

#opened_or_last_checked_at_epochObject (readonly)

Returns the value of attribute opened_or_last_checked_at_epoch.



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

def opened_or_last_checked_at_epoch
  @opened_or_last_checked_at_epoch
end

#propertiesObject (readonly)

Returns the value of attribute properties.



37
38
39
# File 'lib/resilient/circuit_breaker.rb', line 37

def properties
  @properties
end

Class Method Details

.get(key, properties = nil, registry = nil) ⇒ Object

Public: Returns an instance of circuit breaker based on key and registry. Default registry is used if none is provided. If key does not exist, it is registered. If key does exist, it returns registered instance instead of allocating a new instance in order to ensure that state/metrics are the same per key.

See #initialize for docs on key and properties.


18
19
20
21
22
23
# File 'lib/resilient/circuit_breaker.rb', line 18

def self.get(key, properties = nil, registry = nil)
  key = Key.wrap(key)
  (registry || Registry.default).fetch(key) {
    new(key, properties)
  }
end

Instance Method Details

#allow_request?Boolean

Returns:

  • (Boolean)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/resilient/circuit_breaker.rb', line 58

def allow_request?
  instrument("resilient.circuit_breaker.allow_request", key: @key) { |payload|
    payload[:result] = if payload[:force_open] = @properties.force_open
      false
    else
      # we still want to simulate normal behavior/metrics like open, allow
      # single request, etc. so it is possible to test properties in
      # production without impact using force_closed so we run these here
      # instead of in the else below
      allow_request = !open? || allow_single_request?

      if payload[:force_closed] = @properties.force_closed
        true
      else
        allow_request
      end
    end
  }
end

#failureObject



90
91
92
93
94
95
# File 'lib/resilient/circuit_breaker.rb', line 90

def failure
  instrument("resilient.circuit_breaker.failure", key: @key) { |payload|
    metrics.failure
    nil
  }
end

#resetObject



97
98
99
100
101
102
103
104
# File 'lib/resilient/circuit_breaker.rb', line 97

def reset
  instrument("resilient.circuit_breaker.reset", key: @key) { |payload|
    @open = false
    @opened_or_last_checked_at_epoch = 0
    metrics.reset
    nil
  }
end

#successObject



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/resilient/circuit_breaker.rb', line 78

def success
  instrument("resilient.circuit_breaker.success", key: @key) { |payload|
    if @open
      payload[:closed_the_circuit] = true
      close_circuit
    else
      metrics.success
    end
    nil
  }
end