shift-circuit-breaker 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.codeclimate.yml +3 -0
- data/lib/shift/circuit_breaker.rb +1 -0
- data/lib/shift/circuit_breaker/circuit_handler.rb +20 -11
- data/lib/shift/circuit_breaker/version.rb +1 -1
- data/spec/shift/circuit_breaker/circuit_handler_exception_handling_spec.rb +49 -0
- data/spec/shift/circuit_breaker/circuit_handler_monitoring_spec.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bda401bde485debfe14c8dfd0ce54701967e877d2e4839a54b268ed85980daef
|
4
|
+
data.tar.gz: a4f3eb047181e8a48c43de680d27098d90c3c6862cece5664f5e4ae5d3c7a836
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea8da391a6b84eefb37961224417ba54bb7fc967d1e8b9a8178fcaee75ad4a89b75e2f0d7820031f74cedb89aa7f73de2533470b629b4bd898bc7093dd9dfa6c
|
7
|
+
data.tar.gz: 51d1f97c57448055dca2222c0e1d98909bf15903503811b96ca14b4f1b6b7b2a562891d65445e0a0c890bfcacaf84ccf73cfbb5db516c73b9e263360accf55f7
|
data/.codeclimate.yml
CHANGED
@@ -13,9 +13,11 @@ module Shift
|
|
13
13
|
# the defined skip_duration, ie. no operations are executed and the provided fallback is called.
|
14
14
|
#
|
15
15
|
class CircuitHandler
|
16
|
-
attr_accessor :name, :error_threshold, :skip_duration, :exception_classes, :
|
16
|
+
attr_accessor :name, :error_threshold, :skip_duration, :exception_classes, :error_logging_enabled, :error_count
|
17
|
+
attr_accessor :last_error_time, :state, :logger, :monitor
|
17
18
|
|
18
19
|
DEFAULT_EXCEPTION_CLASSES = [Net::OpenTimeout, Net::ReadTimeout, Faraday::TimeoutError, Timeout::Error].freeze
|
20
|
+
DEFAULT_ERROR_LOGGING_STATE = true
|
19
21
|
|
20
22
|
# Initializer creates an instance of the service
|
21
23
|
#
|
@@ -23,24 +25,27 @@ module Shift
|
|
23
25
|
# @param [Integer] error_threshold - The minimum error threshold required for the circuit to be opened/tripped
|
24
26
|
# @param [Integer] skip_duration - The duration in seconds the circuit should be open for before operations are allowed through/executed
|
25
27
|
# @param [Array] additional_exception_classes - Any additional exception classes to rescue along the DEFAULT_EXCEPTION_CLASSES
|
28
|
+
# @param [Boolean] error_logging_enabled - Decided whether to log errors or not. Still they will be monitored
|
26
29
|
# @param [Object] logger - service to handle error logging
|
27
30
|
# @param [Object] monitor - service to monitor metric
|
28
31
|
def initialize(name,
|
29
32
|
error_threshold:,
|
30
33
|
skip_duration:,
|
31
34
|
additional_exception_classes: [],
|
35
|
+
error_logging_enabled: DEFAULT_ERROR_LOGGING_STATE,
|
32
36
|
logger: Shift::CircuitBreaker::CircuitLogger.new,
|
33
37
|
monitor: Shift::CircuitBreaker::CircuitMonitor.new)
|
34
38
|
|
35
|
-
self.name
|
36
|
-
self.error_threshold
|
37
|
-
self.skip_duration
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
self.
|
41
|
-
self.
|
42
|
-
self.
|
43
|
-
self.
|
39
|
+
self.name = name
|
40
|
+
self.error_threshold = error_threshold
|
41
|
+
self.skip_duration = skip_duration
|
42
|
+
self.error_logging_enabled = error_logging_enabled
|
43
|
+
self.exception_classes = (additional_exception_classes | DEFAULT_EXCEPTION_CLASSES)
|
44
|
+
self.logger = logger
|
45
|
+
self.monitor = monitor
|
46
|
+
self.error_count = 0
|
47
|
+
self.last_error_time = nil
|
48
|
+
self.state = :closed
|
44
49
|
end
|
45
50
|
|
46
51
|
# Performs the given operation within the circuit
|
@@ -98,10 +103,14 @@ module Shift
|
|
98
103
|
def handle_exception(exception, fallback)
|
99
104
|
record_error
|
100
105
|
set_state
|
106
|
+
log_errors(exception)
|
101
107
|
monitor.record_metric(name, state)
|
102
|
-
logger.error(circuit_name: name, state: state, error_message: exception.message)
|
103
108
|
fallback.call
|
104
109
|
end
|
110
|
+
|
111
|
+
def log_errors(exception)
|
112
|
+
logger.error(circuit_name: name, state: state, error_message: exception.message) if error_logging_enabled
|
113
|
+
end
|
105
114
|
end
|
106
115
|
end
|
107
116
|
end
|
@@ -137,6 +137,55 @@ module Shift
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
140
|
+
|
141
|
+
context "Error Logging" do
|
142
|
+
let(:default_error_threshold) { 5 }
|
143
|
+
let(:default_skip_duration) { 6 }
|
144
|
+
|
145
|
+
context "when it is enabled" do
|
146
|
+
it "should log errors" do
|
147
|
+
# Arrange
|
148
|
+
operation_stub = instance_double("Operation")
|
149
|
+
fallback_stub = instance_double("Fallback")
|
150
|
+
error_logger = instance_double("Error")
|
151
|
+
|
152
|
+
allow(operation_stub).to receive(:perform_task).and_raise(Timeout::Error, "Request Timeout")
|
153
|
+
allow(error_logger).to receive(:error).and_return({})
|
154
|
+
# Act
|
155
|
+
cb = described_class.new(:test_circuit_breaker, error_threshold: default_error_threshold, skip_duration: default_skip_duration, logger: error_logger)
|
156
|
+
operation_result = cb.call(operation: -> { operation_stub.perform_task }, fallback: -> { fallback_stub })
|
157
|
+
|
158
|
+
# Assert
|
159
|
+
aggregate_failures do
|
160
|
+
expect(operation_result).to eq(fallback_stub)
|
161
|
+
expect(cb.error_count).to eq(1)
|
162
|
+
expect(error_logger).to have_received(:error)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when it is disabled" do
|
168
|
+
it "should not log errors" do
|
169
|
+
# Arrange
|
170
|
+
operation_stub = instance_double("Operation")
|
171
|
+
fallback_stub = instance_double("Fallback")
|
172
|
+
error_logger = instance_double("Error")
|
173
|
+
|
174
|
+
allow(operation_stub).to receive(:perform_task).and_raise(Timeout::Error, "Request Timeout")
|
175
|
+
allow(error_logger).to receive(:error).and_return({})
|
176
|
+
# Act
|
177
|
+
cb = described_class.new(:test_circuit_breaker, error_threshold: default_error_threshold, skip_duration: default_skip_duration, error_logging_enabled: false, logger: error_logger)
|
178
|
+
operation_result = cb.call(operation: -> { operation_stub.perform_task }, fallback: -> { fallback_stub })
|
179
|
+
|
180
|
+
# Assert
|
181
|
+
aggregate_failures do
|
182
|
+
expect(operation_result).to eq(fallback_stub)
|
183
|
+
expect(cb.error_count).to eq(1)
|
184
|
+
expect(error_logger).not_to have_received(:error)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
140
189
|
end
|
141
190
|
end
|
142
191
|
end
|
@@ -20,7 +20,7 @@ module Shift
|
|
20
20
|
operation_stub = instance_double("Operation")
|
21
21
|
fallback_stub = instance_double("Fallback")
|
22
22
|
expected_result_stub = instance_double("ExpectedResult")
|
23
|
-
|
23
|
+
|
24
24
|
allow(monitor_stub).to receive(:record_metric)
|
25
25
|
allow(operation_stub).to receive(:perform_task).and_return(expected_result_stub)
|
26
26
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shift-circuit-breaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mufudzi Masaire
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -223,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
223
|
version: '0'
|
224
224
|
requirements: []
|
225
225
|
rubyforge_project:
|
226
|
-
rubygems_version: 2.
|
226
|
+
rubygems_version: 2.7.7
|
227
227
|
signing_key:
|
228
228
|
specification_version: 4
|
229
229
|
summary: A generic implementation of the Circuit Breaker pattern in Ruby
|