circuit_breakage 1.0.0 → 1.1.0
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 +4 -4
- data/README.md +6 -0
- data/lib/circuit_breakage/breaker.rb +10 -4
- data/lib/circuit_breakage/version.rb +1 -1
- data/spec/breaker_spec.rb +82 -0
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cba4ea6a897024a9a64f381298b155806e47ade7
|
4
|
+
data.tar.gz: bda065d0f7132b76891004752add0cc948bcfc6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04e698f1eff6b98ad18a4ad6359c96db40d7756a3bec6c04c1e44f78aecf5f05781cd1f506631139535c1ee9f8c47585a915750e8d44e3dcafa79eb0cf4196c7
|
7
|
+
data.tar.gz: 9d5cfd0d6bf4e8b3ba7ef1f349e28f27ab92b9951c3dde89a94bc30e7ff0b5bb43bc3eabcdd79600a3f60a445c1a6112d5748a9098cf30e036a210f9f626fadd
|
data/README.md
CHANGED
@@ -18,10 +18,16 @@ proc = ->(*args) do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
breaker = CircuitBreakage::Breaker.new(proc)
|
21
|
+
|
22
|
+
# These options are required.
|
21
23
|
breaker.failure_threshold = 3 # only 3 failures before tripping circuit
|
22
24
|
breaker.duration = 10 # 10 seconds before retry
|
23
25
|
breaker.timeout = 0.5 # 500 milliseconds allowed before auto-fail
|
24
26
|
|
27
|
+
# These options are, uh, optional.
|
28
|
+
breaker.only_trip_on = [ExpensiveFailureException]
|
29
|
+
breaker.never_trip_on = [CheapUnimportantFailureException]
|
30
|
+
|
25
31
|
begin
|
26
32
|
breaker.call(*some_args) # args are passed through to the proc
|
27
33
|
rescue CircuitBreakage::CircuitOpen
|
@@ -10,16 +10,21 @@ module CircuitBreakage
|
|
10
10
|
class Breaker
|
11
11
|
attr_accessor :failure_count, :last_failed, :state, :block
|
12
12
|
attr_accessor :failure_threshold, :duration, :timeout, :last_exception
|
13
|
+
attr_accessor :only_trip_on, :never_trip_on
|
13
14
|
|
14
|
-
DEFAULT_FAILURE_THRESHOLD = 5
|
15
|
-
DEFAULT_DURATION = 300
|
16
|
-
DEFAULT_TIMEOUT = 10
|
15
|
+
DEFAULT_FAILURE_THRESHOLD = 5 # Number of failures required to trip circuit
|
16
|
+
DEFAULT_DURATION = 300 # Number of seconds the circuit stays tripped
|
17
|
+
DEFAULT_TIMEOUT = 10 # Number of seconds before the call times out
|
18
|
+
DEFAULT_ONLY_TRIP_ON = [Exception] # Exceptions that trigger the breaker
|
19
|
+
DEFAULT_NEVER_TRIP_ON = [] # Exceptions that won't trigger the breaker
|
17
20
|
|
18
21
|
def initialize(block=nil)
|
19
22
|
self.block = block
|
20
23
|
self.failure_threshold = DEFAULT_FAILURE_THRESHOLD
|
21
24
|
self.duration = DEFAULT_DURATION
|
22
25
|
self.timeout = DEFAULT_TIMEOUT
|
26
|
+
self.only_trip_on = DEFAULT_ONLY_TRIP_ON
|
27
|
+
self.never_trip_on = DEFAULT_NEVER_TRIP_ON
|
23
28
|
self.failure_count ||= 0
|
24
29
|
self.last_failed ||= 0
|
25
30
|
self.state ||= 'closed'
|
@@ -55,7 +60,8 @@ module CircuitBreakage
|
|
55
60
|
handle_success
|
56
61
|
|
57
62
|
return ret_value
|
58
|
-
rescue
|
63
|
+
rescue *self.only_trip_on => e
|
64
|
+
raise if never_trip_on.any? { |t| e.instance_of?(t) }
|
59
65
|
handle_failure(e)
|
60
66
|
end
|
61
67
|
|
data/spec/breaker_spec.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
module CircuitBreakage
|
2
|
+
class VerySpecificException < StandardError
|
3
|
+
end
|
4
|
+
|
2
5
|
describe Breaker do
|
3
6
|
let(:breaker) { Breaker.new(block) }
|
4
7
|
let(:block) { ->(x) { return x } }
|
@@ -78,6 +81,85 @@ module CircuitBreakage
|
|
78
81
|
expect { breaker.call(arg) }.to raise_exception(CircuitBreakage::CircuitTimeout)
|
79
82
|
end
|
80
83
|
end
|
84
|
+
|
85
|
+
context 'with specific exceptions defined' do
|
86
|
+
before do
|
87
|
+
breaker.only_trip_on = [VerySpecificException]
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'and the call fails with one of the specific exceptions' do
|
91
|
+
let(:block) { ->(_) { raise VerySpecificException } }
|
92
|
+
|
93
|
+
it { is_expected.to change { breaker.failure_count }.by(1) }
|
94
|
+
it { is_expected.to change { breaker.last_failed } }
|
95
|
+
it { is_expected.to change { breaker.last_exception }.from(nil) }
|
96
|
+
|
97
|
+
it 'raises the exception that caused the failure' do
|
98
|
+
expect { breaker.call(arg) }.to raise_exception(VerySpecificException)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'and the call fails with a different exception (including timeouts)' do
|
103
|
+
let(:block) { ->(_) { raise Timeout::Error } }
|
104
|
+
|
105
|
+
it { is_expected.not_to change { breaker.failure_count } }
|
106
|
+
it { is_expected.not_to change { breaker.last_failed } }
|
107
|
+
it { is_expected.not_to change { breaker.last_exception } }
|
108
|
+
|
109
|
+
it 'raises the exception that caused the failure' do
|
110
|
+
expect { breaker.call(arg) }.to raise_exception(Timeout::Error)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with specific exceptions excluded' do
|
116
|
+
before do
|
117
|
+
breaker.never_trip_on = [VerySpecificException]
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'and the call fails with one of the specific exceptions' do
|
121
|
+
let(:block) { ->(_) { raise VerySpecificException } }
|
122
|
+
|
123
|
+
it { is_expected.not_to change { breaker.failure_count } }
|
124
|
+
it { is_expected.not_to change { breaker.last_failed } }
|
125
|
+
it { is_expected.not_to change { breaker.last_exception } }
|
126
|
+
|
127
|
+
it 'raises the exception that caused the failure' do
|
128
|
+
expect { breaker.call(arg) }.to raise_exception(VerySpecificException)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'and the call fails with a different exception' do
|
133
|
+
let(:block) { ->(_) { raise RuntimeError } }
|
134
|
+
|
135
|
+
it { is_expected.to change { breaker.failure_count }.by(1) }
|
136
|
+
it { is_expected.to change { breaker.last_failed } }
|
137
|
+
it { is_expected.to change { breaker.last_exception }.from(nil) }
|
138
|
+
|
139
|
+
it 'raises the exception that caused the failure' do
|
140
|
+
expect { breaker.call(arg) }.to raise_exception(RuntimeError)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with overlapping whitelisted and blacklisted exceptions' do
|
146
|
+
before do
|
147
|
+
breaker.only_trip_on = [StandardError]
|
148
|
+
breaker.never_trip_on = [VerySpecificException] # inherits from StandardError
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'and the call fails with an overlapped exception' do
|
152
|
+
let(:block) { ->(_) { raise VerySpecificException } }
|
153
|
+
|
154
|
+
it { is_expected.not_to change { breaker.failure_count } }
|
155
|
+
it { is_expected.not_to change { breaker.last_failed } }
|
156
|
+
it { is_expected.not_to change { breaker.last_exception } }
|
157
|
+
|
158
|
+
it 'raises the exception that caused the failure' do
|
159
|
+
expect { breaker.call(arg) }.to raise_exception(VerySpecificException)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
81
163
|
end
|
82
164
|
|
83
165
|
context 'when the circuit is open' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: circuit_breakage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Hyland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
110
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.4.5
|
112
112
|
signing_key:
|
113
113
|
specification_version: 4
|
114
114
|
summary: Provides a simple circuit breaker pattern.
|
@@ -116,4 +116,3 @@ test_files:
|
|
116
116
|
- spec/breaker_spec.rb
|
117
117
|
- spec/redis_backed_breaker_spec.rb
|
118
118
|
- spec/spec_helper.rb
|
119
|
-
has_rdoc:
|