circuit_breaker 1.0.1 → 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.
- data/History.txt +4 -0
- data/README.txt +1 -0
- data/circuit_breaker.gemspec +1 -1
- data/lib/circuit_breaker/circuit_handler.rb +9 -2
- data/lib/circuit_breaker/version.rb +1 -1
- data/spec/circuit_breaker_spec.rb +33 -3
- metadata +79 -111
data/History.txt
CHANGED
data/README.txt
CHANGED
data/circuit_breaker.gemspec
CHANGED
@@ -23,6 +23,11 @@ class CircuitBreaker::CircuitHandler
|
|
23
23
|
#
|
24
24
|
attr_accessor :invocation_timeout
|
25
25
|
|
26
|
+
#
|
27
|
+
# The exceptions which should be ignored if happens, they are not counted as failures
|
28
|
+
#
|
29
|
+
attr_accessor :excluded_exceptions
|
30
|
+
|
26
31
|
#
|
27
32
|
# Optional logger.
|
28
33
|
#
|
@@ -31,12 +36,14 @@ class CircuitBreaker::CircuitHandler
|
|
31
36
|
DEFAULT_FAILURE_THRESHOLD = 5
|
32
37
|
DEFAULT_FAILURE_TIMEOUT = 5
|
33
38
|
DEFAULT_INVOCATION_TIMEOUT = 30
|
39
|
+
DEFAULT_EXCLUDED_EXCEPTIONS= []
|
34
40
|
|
35
41
|
def initialize(logger = nil)
|
36
42
|
@logger = logger
|
37
43
|
@failure_threshold = DEFAULT_FAILURE_THRESHOLD
|
38
44
|
@failure_timeout = DEFAULT_FAILURE_TIMEOUT
|
39
45
|
@invocation_timeout = DEFAULT_INVOCATION_TIMEOUT
|
46
|
+
@excluded_exceptions = DEFAULT_EXCLUDED_EXCEPTIONS
|
40
47
|
end
|
41
48
|
|
42
49
|
#
|
@@ -61,8 +68,8 @@ class CircuitBreaker::CircuitHandler
|
|
61
68
|
out = method[*args]
|
62
69
|
on_success(circuit_state)
|
63
70
|
end
|
64
|
-
rescue Exception
|
65
|
-
on_failure(circuit_state)
|
71
|
+
rescue Exception => e
|
72
|
+
on_failure(circuit_state) unless @excluded_exceptions.include?(e.class)
|
66
73
|
raise
|
67
74
|
end
|
68
75
|
return out
|
@@ -3,6 +3,9 @@ require 'logger'
|
|
3
3
|
|
4
4
|
describe CircuitBreaker do
|
5
5
|
|
6
|
+
class SpecificException < Exception; end
|
7
|
+
class NotFoundException < Exception; end
|
8
|
+
|
6
9
|
class TestClass
|
7
10
|
|
8
11
|
include CircuitBreaker
|
@@ -36,9 +39,17 @@ describe CircuitBreaker do
|
|
36
39
|
"unresponsive method returned"
|
37
40
|
end
|
38
41
|
|
42
|
+
def raise_specific_error_method
|
43
|
+
if @failure == true
|
44
|
+
raise SpecificException.new "SPECIFIC FAIL"
|
45
|
+
end
|
46
|
+
|
47
|
+
raise NotFoundException.new "NOT FOUND FAIL"
|
48
|
+
end
|
49
|
+
|
39
50
|
# Register this method with the circuit breaker...
|
40
51
|
#
|
41
|
-
circuit_method :call_external_method, :second_method, :unresponsive_method
|
52
|
+
circuit_method :call_external_method, :second_method, :unresponsive_method, :raise_specific_error_method
|
42
53
|
|
43
54
|
#
|
44
55
|
# Define what needs to be set for configuration...
|
@@ -48,11 +59,13 @@ describe CircuitBreaker do
|
|
48
59
|
handler.failure_threshold = 5
|
49
60
|
handler.failure_timeout = 5
|
50
61
|
handler.invocation_timeout = 1
|
62
|
+
handler.excluded_exceptions = [NotFoundException]
|
51
63
|
end
|
52
64
|
|
53
65
|
end
|
54
66
|
|
55
67
|
before(:each) do
|
68
|
+
TestClass.circuit_handler.failure_threshold = 5
|
56
69
|
@test_object = TestClass.new()
|
57
70
|
end
|
58
71
|
|
@@ -113,9 +126,26 @@ describe CircuitBreaker do
|
|
113
126
|
@test_object.circuit_state.failure_count.should == 1
|
114
127
|
end
|
115
128
|
|
116
|
-
it 'should
|
129
|
+
it 'should increment the failure count when the method takes too long to return' do
|
117
130
|
lambda { @test_object.unresponsive_method }.should raise_error(CircuitBreaker::CircuitBrokenException)
|
118
|
-
@test_object.circuit_state.
|
131
|
+
@test_object.circuit_state.closed?.should == true
|
132
|
+
@test_object.circuit_state.failure_count.should == 1
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "and some exceptions not indicates a circuit problem" do
|
136
|
+
it 'should not increment the failure count when a failure of a specific type occurs' do
|
137
|
+
@test_object.fail!
|
138
|
+
|
139
|
+
lambda { @test_object.raise_specific_error_method }.should raise_error(SpecificException)
|
140
|
+
@test_object.circuit_state.closed?.should == true
|
141
|
+
@test_object.circuit_state.failure_count.should == 1
|
142
|
+
|
143
|
+
@test_object.succeed!
|
144
|
+
|
145
|
+
lambda { @test_object.raise_specific_error_method }.should raise_error(NotFoundException)
|
146
|
+
@test_object.circuit_state.closed?.should == true
|
147
|
+
@test_object.circuit_state.failure_count.should == 1
|
148
|
+
end
|
119
149
|
end
|
120
150
|
|
121
151
|
end
|
metadata
CHANGED
@@ -1,112 +1,87 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: circuit_breaker
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 1.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Will Sargent
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-04-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: aasm
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
segments:
|
30
|
-
- 0
|
31
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
32
22
|
type: :runtime
|
33
|
-
version_requirements: *id001
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: rake
|
36
23
|
prerelease: false
|
37
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
25
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
46
38
|
type: :development
|
47
|
-
version_requirements: *id002
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: rspec
|
50
39
|
prerelease: false
|
51
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
41
|
none: false
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
60
54
|
type: :development
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
include CircuitBreaker
|
85
|
-
|
86
|
-
def call_remote_service() ...
|
87
|
-
|
88
|
-
circuit_method :call_remote_service
|
89
|
-
|
90
|
-
# Optional
|
91
|
-
circuit_handler do |handler|
|
92
|
-
handler.logger = Logger.new(STDOUT)
|
93
|
-
handler.failure_threshold = 5
|
94
|
-
handler.failure_timeout = 5
|
95
|
-
end
|
96
|
-
|
97
|
-
# Optional
|
98
|
-
circuit_handler_class MyCustomCircuitHandler
|
99
|
-
end
|
100
|
-
email:
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: ! "CircuitBreaker is a relatively simple Ruby mixin that will wrap\n
|
63
|
+
a call to a given service in a circuit breaker pattern.\n\n The circuit starts off
|
64
|
+
\"closed\" meaning that all calls will go through.\n However, consecutive failures
|
65
|
+
are recorded and after a threshold is reached,\n the circuit will \"trip\", setting
|
66
|
+
the circuit into an \"open\" state.\n\n In an \"open\" state, every call to the
|
67
|
+
service will fail by raising\n CircuitBrokenException.\n\n The circuit will remain
|
68
|
+
in an \"open\" state until the failure timeout has\n elapsed.\n\n After the failure_timeout
|
69
|
+
has elapsed, the circuit will go into\n a \"half open\" state and the call will
|
70
|
+
go through. A failure will\n immediately pop the circuit open again, and a success
|
71
|
+
will close the\n circuit and reset the failure count.\n\n require 'circuit_breaker'\n
|
72
|
+
\ class TestService\n\n include CircuitBreaker\n\n def call_remote_service()
|
73
|
+
...\n\n circuit_method :call_remote_service\n\n # Optional\n circuit_handler
|
74
|
+
do |handler|\n handler.logger = Logger.new(STDOUT)\n handler.failure_threshold
|
75
|
+
= 5\n handler.failure_timeout = 5\n end\n\n # Optional\n circuit_handler_class
|
76
|
+
MyCustomCircuitHandler\n end"
|
77
|
+
email:
|
101
78
|
- will.sargent@gmail.com
|
102
79
|
executables: []
|
103
|
-
|
104
80
|
extensions: []
|
105
|
-
|
106
|
-
extra_rdoc_files:
|
81
|
+
extra_rdoc_files:
|
107
82
|
- History.txt
|
108
83
|
- README.txt
|
109
|
-
files:
|
84
|
+
files:
|
110
85
|
- .gitignore
|
111
86
|
- .rspec
|
112
87
|
- Gemfile
|
@@ -123,39 +98,32 @@ files:
|
|
123
98
|
- spec/spec_helper.rb
|
124
99
|
homepage: http://github.com/wsargent/circuit_breaker
|
125
100
|
licenses: []
|
126
|
-
|
127
101
|
post_install_message:
|
128
|
-
rdoc_options:
|
102
|
+
rdoc_options:
|
129
103
|
- --main
|
130
104
|
- README.txt
|
131
105
|
- --charset=UTF-8
|
132
|
-
require_paths:
|
106
|
+
require_paths:
|
133
107
|
- lib
|
134
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
109
|
none: false
|
136
|
-
requirements:
|
137
|
-
- -
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
|
140
|
-
|
141
|
-
- 0
|
142
|
-
version: "0"
|
143
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
115
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
|
149
|
-
segments:
|
150
|
-
- 0
|
151
|
-
version: "0"
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
152
120
|
requirements: []
|
153
|
-
|
154
121
|
rubyforge_project: will_sargent
|
155
|
-
rubygems_version: 1.8.
|
122
|
+
rubygems_version: 1.8.23
|
156
123
|
signing_key:
|
157
124
|
specification_version: 3
|
158
|
-
summary: CircuitBreaker is a relatively simple Ruby mixin that will wrap a call to
|
159
|
-
|
125
|
+
summary: CircuitBreaker is a relatively simple Ruby mixin that will wrap a call to
|
126
|
+
a given service in a circuit breaker pattern
|
127
|
+
test_files:
|
160
128
|
- spec/circuit_breaker_spec.rb
|
161
129
|
- spec/spec_helper.rb
|