circuit_breakage 0.1.3 → 0.2.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 +5 -5
- data/lib/circuit_breakage.rb +3 -3
- data/lib/circuit_breakage/breaker.rb +6 -3
- data/lib/circuit_breakage/version.rb +1 -1
- data/spec/breaker_spec.rb +15 -4
- data/spec/redis_backed_breaker_spec.rb +6 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5aeb1835130f99946eddad6d46d8f01dd44a0fed
|
4
|
+
data.tar.gz: bdd92ef38ba1a708da8ac1cab7e9bb34c1b4fe8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73d6b93182c3bd07d75196ac21c3fb7a7ca47259183c57a512ae131821eddfb035abc65509cd3d62a9cb3deae30f148aa3d352d9a12c4362e9297ddf397bcc18
|
7
|
+
data.tar.gz: f7f86f802260ab60af42d2db4031ac62110ff8081bcc681e74be062a4a376af5e00a721e33df9cd50f3dd14d33472710d70cf7fe7bdaf864de72cc41a444892a
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# CircuitBreakage
|
2
2
|
|
3
|
-
A simple
|
4
|
-
|
3
|
+
A simple circuit breaker implementation in Ruby with a timeout. A circuit
|
4
|
+
breaker wraps a potentially troublesome block of code and will "trip" the
|
5
5
|
circuit (ie, stop trying to run the code) if it sees too many failures. After
|
6
6
|
a configurable amount of time, the circuit breaker will retry.
|
7
7
|
|
@@ -24,9 +24,9 @@ breaker.timeout = 0.5 # 500 milliseconds allowed before auto-fail
|
|
24
24
|
|
25
25
|
begin
|
26
26
|
breaker.call(*some_args) # args are passed through to block
|
27
|
-
rescue
|
27
|
+
rescue CircuitBreakage::CircuitOpen
|
28
28
|
puts "Too many recent failures!"
|
29
|
-
rescue
|
29
|
+
rescue CircuitBreakage::CircuitTimeout
|
30
30
|
puts "Operation timed out!"
|
31
31
|
end
|
32
32
|
```
|
@@ -34,7 +34,7 @@ end
|
|
34
34
|
A "failure" in this context means that the block either raised an exception or
|
35
35
|
timed out.
|
36
36
|
|
37
|
-
### Redis-
|
37
|
+
### Redis-Backed "Shared" Circuit Breakers
|
38
38
|
|
39
39
|
The unique feature of this particular Circuit Breaker gem is that it also
|
40
40
|
supports shared state via Redis, using the SETNX and GETSET commands. This
|
data/lib/circuit_breakage.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative "circuit_breakage/version"
|
2
|
+
require_relative "circuit_breakage/breaker"
|
3
|
+
require_relative "circuit_breakage/redis_backed_breaker"
|
@@ -9,7 +9,7 @@ module CircuitBreakage
|
|
9
9
|
#
|
10
10
|
class Breaker
|
11
11
|
attr_accessor :failure_count, :last_failed, :state, :block
|
12
|
-
attr_accessor :failure_threshold, :duration, :timeout
|
12
|
+
attr_accessor :failure_threshold, :duration, :timeout, :last_exception
|
13
13
|
|
14
14
|
DEFAULT_FAILURE_THRESHOLD = 5 # Number of failures required to trip circuit
|
15
15
|
DEFAULT_DURATION = 300 # Number of seconds the circuit stays tripped
|
@@ -54,7 +54,7 @@ module CircuitBreakage
|
|
54
54
|
|
55
55
|
return ret_value
|
56
56
|
rescue Exception => e
|
57
|
-
handle_failure
|
57
|
+
handle_failure(e)
|
58
58
|
end
|
59
59
|
|
60
60
|
def time_to_retry?
|
@@ -66,12 +66,15 @@ module CircuitBreakage
|
|
66
66
|
self.state = 'closed'
|
67
67
|
end
|
68
68
|
|
69
|
-
def handle_failure
|
69
|
+
def handle_failure(error)
|
70
70
|
self.last_failed = Time.now
|
71
71
|
self.failure_count += 1
|
72
72
|
if self.failure_count >= self.failure_threshold
|
73
73
|
self.state = 'open'
|
74
74
|
end
|
75
|
+
|
76
|
+
self.last_exception = error
|
77
|
+
raise(error)
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
data/spec/breaker_spec.rb
CHANGED
@@ -10,7 +10,7 @@ module CircuitBreakage
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '#call' do
|
13
|
-
subject { -> { breaker.call(arg) } }
|
13
|
+
subject { -> { breaker.call(arg) rescue nil} }
|
14
14
|
let(:arg) { 'This is an argument.' }
|
15
15
|
|
16
16
|
context 'when the circuit is closed' do
|
@@ -29,10 +29,15 @@ module CircuitBreakage
|
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'and the call fails' do
|
32
|
-
let(:block) { -> { raise 'some error' } }
|
32
|
+
let(:block) { ->(_) { raise 'some error' } }
|
33
33
|
|
34
34
|
it { is_expected.to change { breaker.failure_count }.by(1) }
|
35
35
|
it { is_expected.to change { breaker.last_failed } }
|
36
|
+
it { is_expected.to change { breaker.last_exception }.from(nil) }
|
37
|
+
|
38
|
+
it 'raises the exception that caused the failure' do
|
39
|
+
expect { breaker.call(arg) }.to raise_exception('some error')
|
40
|
+
end
|
36
41
|
|
37
42
|
context 'and the failure count exceeds the failure threshold' do
|
38
43
|
before { breaker.failure_count = breaker.failure_threshold }
|
@@ -46,7 +51,11 @@ module CircuitBreakage
|
|
46
51
|
before { breaker.timeout = 0.1 }
|
47
52
|
|
48
53
|
it 'counts as a failure' do
|
49
|
-
expect { breaker.call(arg) }.to change { breaker.failure_count }.by(1)
|
54
|
+
expect { breaker.call(arg) rescue nil }.to change { breaker.failure_count }.by(1)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'raises CircuitBreakage::CircuitTimeout' do
|
58
|
+
expect { breaker.call(arg) }.to raise_exception(CircuitBreakage::CircuitTimeout)
|
50
59
|
end
|
51
60
|
end
|
52
61
|
end
|
@@ -57,7 +66,9 @@ module CircuitBreakage
|
|
57
66
|
context 'before the retry_time' do
|
58
67
|
before { breaker.last_failed = Time.now - breaker.duration + 30 }
|
59
68
|
|
60
|
-
it
|
69
|
+
it 'raises CircuitBreakage::CircuitOpen' do
|
70
|
+
expect { breaker.call(arg) }.to raise_error(CircuitOpen)
|
71
|
+
end
|
61
72
|
end
|
62
73
|
|
63
74
|
context 'after the retry time' do
|
@@ -9,7 +9,7 @@ module CircuitBreakage
|
|
9
9
|
let(:block) { ->(x) { return x } }
|
10
10
|
|
11
11
|
describe '#call' do
|
12
|
-
subject { -> { breaker.call(arg) } }
|
12
|
+
subject { -> { breaker.call(arg) rescue nil } }
|
13
13
|
let(:arg) { 'This is an argument.' }
|
14
14
|
|
15
15
|
context 'when the circuit is closed' do
|
@@ -28,7 +28,7 @@ module CircuitBreakage
|
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'and the call fails' do
|
31
|
-
let(:block) { -> { raise 'some error' } }
|
31
|
+
let(:block) { ->(_) { raise 'some error' } }
|
32
32
|
|
33
33
|
it { is_expected.to change { breaker.failure_count }.by(1) }
|
34
34
|
it { is_expected.to change { breaker.last_failed } }
|
@@ -45,7 +45,7 @@ module CircuitBreakage
|
|
45
45
|
before { breaker.timeout = 0.1 }
|
46
46
|
|
47
47
|
it 'counts as a failure' do
|
48
|
-
expect { breaker.call(arg) }.to change { breaker.failure_count }.by(1)
|
48
|
+
expect { breaker.call(arg) rescue nil }.to change { breaker.failure_count }.by(1)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -56,7 +56,9 @@ module CircuitBreakage
|
|
56
56
|
context 'before the retry_time' do
|
57
57
|
before { breaker.last_failed = Time.now - breaker.duration + 30 }
|
58
58
|
|
59
|
-
it
|
59
|
+
it 'raises CircuitBreakage::CircuitOpen' do
|
60
|
+
expect { breaker.call(arg) }.to raise_error(CircuitOpen)
|
61
|
+
end
|
60
62
|
end
|
61
63
|
|
62
64
|
context 'after the retry time' 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: 0.
|
4
|
+
version: 0.2.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: 2015-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|