Class: Faulty::Status
- Inherits:
-
Struct
- Object
- Struct
- Faulty::Status
- Includes:
- ImmutableOptions
- Defined in:
- lib/faulty/status.rb
Overview
The status of a circuit
Includes information like the state and locks. Also calculates whether a circuit can be run, or if it has failed a threshold.
Constant Summary collapse
- STATES =
The allowed state values
%i[ open closed ].freeze
- LOCKS =
The allowed lock values
%i[ open closed ].freeze
Instance Attribute Summary collapse
-
#failure_rate ⇒ Float
readonly
A number from 0 to 1 representing the percentage of failures for the circuit.
-
#lock ⇒ :open, ...
readonly
If the circuit is locked, the state that it is locked in.
-
#opened_at ⇒ Integer?
readonly
If the circuit is open, the timestamp that it was opened.
-
#options ⇒ Circuit::Options
readonly
The options for the circuit.
-
#sample_size ⇒ Integer
readonly
The number of samples used to calculate the failure rate.
-
#state ⇒ :open, :closed
readonly
The stored circuit state.
-
#stub ⇒ Boolean
readonly
True if this status is a stub and not calculated from the storage backend.
Class Method Summary collapse
-
.from_entries(entries, **hash) ⇒ Status
Create a new
Statusfrom a list of circuit runs.
Instance Method Summary collapse
-
#can_run? ⇒ Boolean
Whether the circuit can be run.
-
#closed? ⇒ Boolean
Whether the circuit is closed.
- #defaults ⇒ Object
-
#fails_threshold? ⇒ Boolean
Whether the circuit fails the sample size and rate thresholds.
- #finalize ⇒ Object
-
#half_open? ⇒ Boolean
Whether the circuit is half-open.
-
#locked_closed? ⇒ Boolean
Whether the circuit is locked closed.
-
#locked_open? ⇒ Boolean
Whether the circuit is locked open.
-
#open? ⇒ Boolean
Whether the circuit is open.
- #required ⇒ Object
Methods included from ImmutableOptions
#dup_with, #initialize, #setup
Instance Attribute Details
#failure_rate ⇒ Float (readonly)
Returns A number from 0 to 1 representing the percentage of failures for the circuit. For exmaple 0.5 represents a 50% failure rate.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#lock ⇒ :open, ... (readonly)
Returns If the circuit is locked, the state that
it is locked in. Default nil.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#opened_at ⇒ Integer? (readonly)
Returns If the circuit is open, the timestamp that it was
opened. This is not necessarily reset when the circuit is closed.
Default nil.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#options ⇒ Circuit::Options (readonly)
Returns The options for the circuit.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#sample_size ⇒ Integer (readonly)
Returns The number of samples used to calculate the failure rate.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#state ⇒ :open, :closed (readonly)
Returns The stored circuit state. This is always open
or closed. Half-open is calculated from the current time. For that
reason, calling state directly should be avoided. Instead use the
status methods #open?, #closed?, and #half_open?.
Default :closed.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
#stub ⇒ Boolean (readonly)
True if this status is a stub and not calculated from
the storage backend. Used by Faulty::Storage::FaultTolerantProxy when
returning the status for an offline storage backend. Default false.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/faulty/status.rb', line 33 Status = Struct.new( :state, :lock, :opened_at, :failure_rate, :sample_size, :options, :stub ) do include ImmutableOptions # The allowed state values STATES = %i[ open closed ].freeze # The allowed lock values LOCKS = %i[ open closed ].freeze # Create a new `Status` from a list of circuit runs # # For storage backends that store entries, this automatically calculates # failure_rate and sample size. # # @param entries [Array<Array>] An array of entry tuples. See # {Circuit#history} for details # @param hash [Hash] The status attributes minus failure_rate and # sample_size # @return [Status] def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end # Whether the circuit is open # # This is mutually exclusive with {#closed?} and {#half_open?} # # @return [Boolean] True if open def open? state == :open && opened_at + .cool_down > Faulty.current_time end # Whether the circuit is closed # # This is mutually exclusive with {#open?} and {#half_open?} # # @return [Boolean] True if closed def closed? state == :closed end # Whether the circuit is half-open # # This is mutually exclusive with {#open?} and {#closed?} # # @return [Boolean] True if half-open def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end # Whether the circuit is locked open # # @return [Boolean] True if locked open def locked_open? lock == :open end # Whether the circuit is locked closed # # @return [Boolean] True if locked closed def locked_closed? lock == :closed end # Whether the circuit can be run # # Takes the circuit state, locks and cooldown into account # # @return [Boolean] True if the circuit can be run def can_run? return false if locked_open? closed? || locked_closed? || half_open? end # Whether the circuit fails the sample size and rate thresholds # # @return [Boolean] True if the circuit fails the thresholds def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end def required %i[state failure_rate sample_size options stub] end def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end end |
Class Method Details
.from_entries(entries, **hash) ⇒ Status
Create a new Status from a list of circuit runs
For storage backends that store entries, this automatically calculates failure_rate and sample size.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/faulty/status.rb', line 66 def self.from_entries(entries, **hash) window_start = Faulty.current_time - hash[:options].evaluation_window size = entries.size i = 0 failures = 0 sample_size = 0 # This is a hot loop, and while is slightly faster than each while i < size time, success = entries[i] i += 1 next unless time > window_start sample_size += 1 failures += 1 unless success end new(hash.merge( sample_size: sample_size, failure_rate: sample_size.zero? ? 0.0 : failures.to_f / sample_size )) end |
Instance Method Details
#can_run? ⇒ Boolean
Whether the circuit can be run
Takes the circuit state, locks and cooldown into account
135 136 137 138 139 |
# File 'lib/faulty/status.rb', line 135 def can_run? return false if locked_open? closed? || locked_closed? || half_open? end |
#closed? ⇒ Boolean
Whether the circuit is closed
This is mutually exclusive with #open? and #half_open?
103 104 105 |
# File 'lib/faulty/status.rb', line 103 def closed? state == :closed end |
#defaults ⇒ Object
162 163 164 165 166 167 168 169 |
# File 'lib/faulty/status.rb', line 162 def defaults { state: :closed, failure_rate: 0.0, sample_size: 0, stub: false } end |
#fails_threshold? ⇒ Boolean
Whether the circuit fails the sample size and rate thresholds
144 145 146 147 148 |
# File 'lib/faulty/status.rb', line 144 def fails_threshold? return false if sample_size < .sample_threshold failure_rate >= .rate_threshold end |
#finalize ⇒ Object
150 151 152 153 154 155 156 |
# File 'lib/faulty/status.rb', line 150 def finalize raise ArgumentError, "state must be a symbol in #{self.class}::STATES" unless STATES.include?(state) unless lock.nil? || LOCKS.include?(lock) raise ArgumentError, "lock must be a symbol in #{self.class}::LOCKS or nil" end raise ArgumentError, 'opened_at is required if state is open' if state == :open && opened_at.nil? end |
#half_open? ⇒ Boolean
112 113 114 |
# File 'lib/faulty/status.rb', line 112 def half_open? state == :open && opened_at + .cool_down <= Faulty.current_time end |
#locked_closed? ⇒ Boolean
Whether the circuit is locked closed
126 127 128 |
# File 'lib/faulty/status.rb', line 126 def locked_closed? lock == :closed end |
#locked_open? ⇒ Boolean
Whether the circuit is locked open
119 120 121 |
# File 'lib/faulty/status.rb', line 119 def locked_open? lock == :open end |
#open? ⇒ Boolean
Whether the circuit is open
This is mutually exclusive with #closed? and #half_open?
94 95 96 |
# File 'lib/faulty/status.rb', line 94 def open? state == :open && opened_at + .cool_down > Faulty.current_time end |
#required ⇒ Object
158 159 160 |
# File 'lib/faulty/status.rb', line 158 def required %i[state failure_rate sample_size options stub] end |