Class: Circuitbox::CircuitBreaker
- Inherits:
-
Object
- Object
- Circuitbox::CircuitBreaker
- Defined in:
- lib/circuitbox/circuit_breaker.rb
Constant Summary collapse
- DEFAULTS =
{ sleep_window: 90, volume_threshold: 5, error_threshold: 50, time_window: 60 }.freeze
Instance Attribute Summary collapse
-
#circuit_options ⇒ Object
readonly
Returns the value of attribute circuit_options.
-
#circuit_store ⇒ Object
readonly
Returns the value of attribute circuit_store.
-
#exceptions ⇒ Object
readonly
Returns the value of attribute exceptions.
-
#notifier ⇒ Object
readonly
Returns the value of attribute notifier.
-
#service ⇒ Object
readonly
Returns the value of attribute service.
-
#time_class ⇒ Object
readonly
Returns the value of attribute time_class.
Instance Method Summary collapse
-
#error_rate(failures = failure_count, success = success_count) ⇒ Float
Calculates the current error rate of the circuit.
-
#failure_count ⇒ Integer
Number of Failures the circuit has encountered in the current time window.
-
#initialize(service, options = {}) ⇒ CircuitBreaker
constructor
Initialize a CircuitBreaker.
-
#open? ⇒ Boolean
Check if the circuit is open.
- #option_value(name) ⇒ Object
-
#run(exception: true) { ... } ⇒ Object, Nil
Run the circuit with the given block.
-
#success_count ⇒ Integer
Number of successes the circuit has encountered in the current time window.
-
#try_close_next_time ⇒ Object
If the circuit is open the key indicating that the circuit is open On the next call to run the circuit would run as if it were in the half open state.
Constructor Details
#initialize(service, options = {}) ⇒ CircuitBreaker
Initialize a CircuitBreaker
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/circuitbox/circuit_breaker.rb', line 31 def initialize(service, = {}) @service = service.to_s @circuit_options = DEFAULTS.merge() @circuit_store = .fetch(:circuit_store) { Circuitbox.default_circuit_store } @notifier = .fetch(:notifier) { Circuitbox.default_notifier } if @circuit_options[:timeout_seconds] warn('timeout_seconds was removed in circuitbox 2.0. '\ 'Check the upgrade guide at https://github.com/yammer/circuitbox') end if @circuit_options[:cache] warn('cache was changed to circuit_store in circuitbox 2.0. '\ 'Check the upgrade guide at https://github.com/yammer/circuitbox') end @exceptions = .fetch(:exceptions) raise ArgumentError.new('exceptions must be an array') unless @exceptions.is_a?(Array) @time_class = .fetch(:time_class) { default_time_klass } @state_change_mutex = Mutex.new @open_storage_key = "circuits:#{@service}:open" @half_open_storage_key = "circuits:#{@service}:half_open" check_sleep_window end |
Instance Attribute Details
#circuit_options ⇒ Object (readonly)
Returns the value of attribute circuit_options.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def @circuit_options end |
#circuit_store ⇒ Object (readonly)
Returns the value of attribute circuit_store.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def circuit_store @circuit_store end |
#exceptions ⇒ Object (readonly)
Returns the value of attribute exceptions.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def exceptions @exceptions end |
#notifier ⇒ Object (readonly)
Returns the value of attribute notifier.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def notifier @notifier end |
#service ⇒ Object (readonly)
Returns the value of attribute service.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def service @service end |
#time_class ⇒ Object (readonly)
Returns the value of attribute time_class.
8 9 10 |
# File 'lib/circuitbox/circuit_breaker.rb', line 8 def time_class @time_class end |
Instance Method Details
#error_rate(failures = failure_count, success = success_count) ⇒ Float
Calculates the current error rate of the circuit
109 110 111 112 113 114 |
# File 'lib/circuitbox/circuit_breaker.rb', line 109 def error_rate(failures = failure_count, success = success_count) all_count = failures + success return 0.0 unless all_count.positive? (failures / all_count.to_f) * 100 end |
#failure_count ⇒ Integer
Number of Failures the circuit has encountered in the current time window
119 120 121 |
# File 'lib/circuitbox/circuit_breaker.rb', line 119 def failure_count @circuit_store.load(stat_storage_key('failure'), raw: true).to_i end |
#open? ⇒ Boolean
Check if the circuit is open
102 103 104 |
# File 'lib/circuitbox/circuit_breaker.rb', line 102 def open? @circuit_store.key?(@open_storage_key) end |
#option_value(name) ⇒ Object
58 59 60 61 |
# File 'lib/circuitbox/circuit_breaker.rb', line 58 def option_value(name) value = @circuit_options[name] value.is_a?(Proc) ? value.call : value end |
#run(exception: true) { ... } ⇒ Object, Nil
Run the circuit with the given block. If the circuit is closed or half_open the block will run. If the circuit is open the block will not be run.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/circuitbox/circuit_breaker.rb', line 78 def run(exception: true, &block) if open? skipped! raise Circuitbox::OpenCircuitError.new(@service) if exception else begin response = @notifier.notify_run(@service, &block) success! rescue *@exceptions => e # Other stores could raise an exception that circuitbox is asked to watch. # setting to nil keeps the same behavior as the previous definition of run. response = nil failure! raise Circuitbox::ServiceFailureError.new(@service, e) if exception end end response end |
#success_count ⇒ Integer
Number of successes the circuit has encountered in the current time window
126 127 128 |
# File 'lib/circuitbox/circuit_breaker.rb', line 126 def success_count @circuit_store.load(stat_storage_key('success'), raw: true).to_i end |
#try_close_next_time ⇒ Object
If the circuit is open the key indicating that the circuit is open On the next call to run the circuit would run as if it were in the half open state
This does not reset any of the circuit success/failure state so future failures in the same time window may cause the circuit to open sooner
135 136 137 |
# File 'lib/circuitbox/circuit_breaker.rb', line 135 def try_close_next_time @circuit_store.delete(@open_storage_key) end |