ya_circuit_breaker 0.0.2 → 0.0.3
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/ChangeLog +3 -0
- data/README.md +6 -1
- data/lib/circuit_breaker.rb +13 -5
- data/lib/circuit_breaker/version.rb +1 -1
- data/test/circuit_breaker_test.rb +28 -0
- metadata +12 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ffa87cc6c8a50ade120114ace1c9d8e98e7ba4a
|
4
|
+
data.tar.gz: d119cd8c1448de2b4225114a9dc938e453b8c0a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f64c4eaceb986bc3a70e3a5e60a284eb6fa6d74ba421318ddd49ae99e921445f9a94ffc0a35c3d58d722841cfbfea1842e7967d81a3577a29c7c42b8539b3e5
|
7
|
+
data.tar.gz: e5df6e2f23df1d8a69ebb09d194ecc698eeda630f93506bd64e9ed696519b4256d40bdfea129429dde6ecc1e77cd59723ac068d198c2e0e9242d1930355e9703
|
data/ChangeLog
ADDED
data/README.md
CHANGED
@@ -31,7 +31,10 @@ options = {
|
|
31
31
|
# invocation timeout in seconds
|
32
32
|
invocation_timeout: 0.5,
|
33
33
|
# a list of timeouts for consecutive failures in seconds. can be used for exponential backoff
|
34
|
-
|
34
|
+
# a Proc can be also passed instead, that can operate on a number of retries after circuit breaker trips
|
35
|
+
reset_timeouts: [2, 4, 8, 16, 32, 64, 128], # or Proc.new {|retry| retry * 10}
|
36
|
+
# a list of errors or exceptions that indicates outtage of service
|
37
|
+
errors_handled: [Redis::CommandError]
|
35
38
|
}
|
36
39
|
|
37
40
|
circuit_breaker = CircuitBreaker::Basic.new(options)
|
@@ -44,6 +47,8 @@ rescue CircuitBreaker::CircuitBrokenError
|
|
44
47
|
$stderr.puts "Circuit tripped"
|
45
48
|
rescue Timeout::Error
|
46
49
|
$stderr.puts "Call took too long"
|
50
|
+
resque Redis::CommandError # from errors_handled
|
51
|
+
$stderr.puts "One of the errors indicating outtage of the service"
|
47
52
|
rescue Error
|
48
53
|
$stderr.puts "Error thrown by 'http_api_call'"
|
49
54
|
end
|
data/lib/circuit_breaker.rb
CHANGED
@@ -9,7 +9,8 @@ module CircuitBreaker
|
|
9
9
|
DEFAULTS = {
|
10
10
|
failure_threshold: 5,
|
11
11
|
invocation_timeout: 2,
|
12
|
-
reset_timeouts: 10
|
12
|
+
reset_timeouts: 10,
|
13
|
+
errors_handled: [],
|
13
14
|
}
|
14
15
|
|
15
16
|
attr_reader :failure_count, :last_failure_time, :failure_threshold
|
@@ -18,7 +19,8 @@ module CircuitBreaker
|
|
18
19
|
options = DEFAULTS.merge(options)
|
19
20
|
@failure_threshold = options[:failure_threshold]
|
20
21
|
@invocation_timeout = options[:invocation_timeout]
|
21
|
-
@reset_timeouts = Array(options[:reset_timeouts])
|
22
|
+
@reset_timeouts = options[:reset_timeouts].is_a?(Proc) ? options[:reset_timeouts] : Array(options[:reset_timeouts])
|
23
|
+
@errors_handled = Array(options[:errors_handled])
|
22
24
|
@last_failure_time = nil
|
23
25
|
@failure_count = 0
|
24
26
|
end
|
@@ -50,7 +52,13 @@ module CircuitBreaker
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def reset_timeout
|
53
|
-
@reset_timeouts
|
55
|
+
if @reset_timeouts.is_a? Proc
|
56
|
+
return @reset_timeouts.call retry_counter
|
57
|
+
else
|
58
|
+
index = [@reset_timeouts.size - 1, retry_counter].min
|
59
|
+
@reset_timeouts[index]
|
60
|
+
end
|
61
|
+
|
54
62
|
end
|
55
63
|
|
56
64
|
|
@@ -73,8 +81,8 @@ module CircuitBreaker
|
|
73
81
|
block.call if block_given?
|
74
82
|
end
|
75
83
|
reset!
|
76
|
-
rescue
|
77
|
-
record_failure
|
84
|
+
rescue Exception => e
|
85
|
+
record_failure if e.class == Timeout::Error || @errors_handled.include?(e.class)
|
78
86
|
raise
|
79
87
|
end
|
80
88
|
else
|
@@ -63,6 +63,17 @@ describe CircuitBreaker::Basic do
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
it "should trip after the failure threshold has been exceeded" do
|
67
|
+
circuit_breaker = CircuitBreaker::Basic.new(failure_threshold: 1, invocation_timeout: 0.1, errors_handled: ArgumentError)
|
68
|
+
|
69
|
+
assert_raises ArgumentError do
|
70
|
+
circuit_breaker.execute do
|
71
|
+
raise ArgumentError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
assert circuit_breaker.open?, "Circuit should be open"
|
75
|
+
end
|
76
|
+
|
66
77
|
it "should reset after reset timeout" do
|
67
78
|
reset_timeouts = 0.1
|
68
79
|
circuit_breaker = CircuitBreaker::Basic.new(reset_timeouts: reset_timeouts)
|
@@ -77,6 +88,23 @@ describe CircuitBreaker::Basic do
|
|
77
88
|
assert circuit_breaker.half_open?
|
78
89
|
end
|
79
90
|
|
91
|
+
it "should handle proc as reset timeout" do
|
92
|
+
reset_timeouts = Proc.new {|retry_counter| retry_counter + 1}
|
93
|
+
circuit_breaker = CircuitBreaker::Basic.new(failure_threshold: 1, reset_timeouts: reset_timeouts, errors_handled: ArgumentError)
|
94
|
+
|
95
|
+
assert_raises ArgumentError do
|
96
|
+
circuit_breaker.execute do
|
97
|
+
raise ArgumentError
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
assert circuit_breaker.open?, "Circuit should be open"
|
102
|
+
|
103
|
+
sleep(reset_timeouts.call 1)
|
104
|
+
|
105
|
+
assert circuit_breaker.half_open?
|
106
|
+
end
|
107
|
+
|
80
108
|
it "should change from half open to closed on success" do
|
81
109
|
reset_timeouts = 0.1
|
82
110
|
circuit_breaker = CircuitBreaker::Basic.new(reset_timeouts: reset_timeouts)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ya_circuit_breaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Huesler
|
@@ -9,34 +9,34 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-04-
|
12
|
+
date: 2014-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ~>
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.5'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.5'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
description: Prevent long running external calls from blocking an application
|
@@ -47,8 +47,9 @@ executables: []
|
|
47
47
|
extensions: []
|
48
48
|
extra_rdoc_files: []
|
49
49
|
files:
|
50
|
-
-
|
51
|
-
-
|
50
|
+
- .gitignore
|
51
|
+
- .travis.yml
|
52
|
+
- ChangeLog
|
52
53
|
- Gemfile
|
53
54
|
- LICENSE.txt
|
54
55
|
- README.md
|
@@ -69,17 +70,17 @@ require_paths:
|
|
69
70
|
- lib
|
70
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
72
|
requirements:
|
72
|
-
- -
|
73
|
+
- - '>='
|
73
74
|
- !ruby/object:Gem::Version
|
74
75
|
version: '0'
|
75
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
77
|
requirements:
|
77
|
-
- -
|
78
|
+
- - '>='
|
78
79
|
- !ruby/object:Gem::Version
|
79
80
|
version: '0'
|
80
81
|
requirements: []
|
81
82
|
rubyforge_project:
|
82
|
-
rubygems_version: 2.
|
83
|
+
rubygems_version: 2.0.3
|
83
84
|
signing_key:
|
84
85
|
specification_version: 4
|
85
86
|
summary: Basic circuit breaker in Ruby
|