circuit_breaker 1.0.0 → 1.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in circuit_breaker.gemspec
4
+ gemspec
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ === 1.0.1 / 2011-01-05
2
+
3
+ * Gem dependency issue "rubyist-aasm" is now "aasm" (ttdonovan)
4
+ * Using Bundler for gem management (ttdonovan)
5
+ * Updated the gemspec (ttdonovan)
6
+ * Minor changes to specs (ttdonovan)
7
+
1
8
  === 1.0.0 / 2009-07-13
2
9
 
3
10
  * Initial release
data/README.txt CHANGED
@@ -3,7 +3,6 @@
3
3
  * http://github.com/wsargent/circuit_breaker
4
4
  * http://rdoc.info/projects/wsargent/circuit_breaker
5
5
  * Will Sargent <will.sargent@gmail.com>
6
- * Copyright 2009 Will Sargent
7
6
 
8
7
  == DESCRIPTION:
9
8
 
@@ -25,6 +24,11 @@
25
24
  immediately pop the circuit open again, and a success will close the
26
25
  circuit and reset the failure count.
27
26
 
27
+ For services that can take an unmanagable amount of time to respond an
28
+ invocation timeout threshold is provided. If the service fails to return
29
+ before the invocation_timeout duration has passed, the circuit will "trip",
30
+ setting the circuit into an "open" state.
31
+
28
32
  require 'circuit_breaker'
29
33
  class TestService
30
34
 
@@ -33,12 +37,13 @@
33
37
  def call_remote_service() ...
34
38
 
35
39
  circuit_method :call_remote_service
36
-
40
+
37
41
  # Optional
38
42
  circuit_handler do |handler|
39
43
  handler.logger = Logger.new(STDOUT)
40
44
  handler.failure_threshold = 5
41
45
  handler.failure_timeout = 5
46
+ handler.invocation_timeout = 10
42
47
  end
43
48
 
44
49
  # Optional
@@ -61,174 +66,27 @@
61
66
 
62
67
  == INSTALL:
63
68
 
64
- * gem sources -a http://gems.github.com
65
- * gem install rubyist-aasm
66
- * gem install wsargent_circuit-breaker
69
+ * gem install circuit-breaker
67
70
 
68
71
  == LICENSE:
69
72
 
70
- GNU LESSER GENERAL PUBLIC LICENSE
71
- Version 3, 29 June 2007
72
-
73
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
74
- Everyone is permitted to copy and distribute verbatim copies
75
- of this license document, but changing it is not allowed.
76
-
77
-
78
- This version of the GNU Lesser General Public License incorporates
79
- the terms and conditions of version 3 of the GNU General Public
80
- License, supplemented by the additional permissions listed below.
81
-
82
- 0. Additional Definitions.
83
-
84
- As used herein, "this License" refers to version 3 of the GNU Lesser
85
- General Public License, and the "GNU GPL" refers to version 3 of the GNU
86
- General Public License.
87
-
88
- "The Library" refers to a covered work governed by this License,
89
- other than an Application or a Combined Work as defined below.
90
-
91
- An "Application" is any work that makes use of an interface provided
92
- by the Library, but which is not otherwise based on the Library.
93
- Defining a subclass of a class defined by the Library is deemed a mode
94
- of using an interface provided by the Library.
95
-
96
- A "Combined Work" is a work produced by combining or linking an
97
- Application with the Library. The particular version of the Library
98
- with which the Combined Work was made is also called the "Linked
99
- Version".
100
-
101
- The "Minimal Corresponding Source" for a Combined Work means the
102
- Corresponding Source for the Combined Work, excluding any source code
103
- for portions of the Combined Work that, considered in isolation, are
104
- based on the Application, and not on the Linked Version.
105
-
106
- The "Corresponding Application Code" for a Combined Work means the
107
- object code and/or source code for the Application, including any data
108
- and utility programs needed for reproducing the Combined Work from the
109
- Application, but excluding the System Libraries of the Combined Work.
110
-
111
- 1. Exception to Section 3 of the GNU GPL.
112
-
113
- You may convey a covered work under sections 3 and 4 of this License
114
- without being bound by section 3 of the GNU GPL.
115
-
116
- 2. Conveying Modified Versions.
117
-
118
- If you modify a copy of the Library, and, in your modifications, a
119
- facility refers to a function or data to be supplied by an Application
120
- that uses the facility (other than as an argument passed when the
121
- facility is invoked), then you may convey a copy of the modified
122
- version:
123
-
124
- a) under this License, provided that you make a good faith effort to
125
- ensure that, in the event an Application does not supply the
126
- function or data, the facility still operates, and performs
127
- whatever part of its purpose remains meaningful, or
128
-
129
- b) under the GNU GPL, with none of the additional permissions of
130
- this License applicable to that copy.
131
-
132
- 3. Object Code Incorporating Material from Library Header Files.
133
-
134
- The object code form of an Application may incorporate material from
135
- a header file that is part of the Library. You may convey such object
136
- code under terms of your choice, provided that, if the incorporated
137
- material is not limited to numerical parameters, data structure
138
- layouts and accessors, or small macros, inline functions and templates
139
- (ten or fewer lines in length), you do both of the following:
140
-
141
- a) Give prominent notice with each copy of the object code that the
142
- Library is used in it and that the Library and its use are
143
- covered by this License.
144
-
145
- b) Accompany the object code with a copy of the GNU GPL and this license
146
- document.
147
-
148
- 4. Combined Works.
149
-
150
- You may convey a Combined Work under terms of your choice that,
151
- taken together, effectively do not restrict modification of the
152
- portions of the Library contained in the Combined Work and reverse
153
- engineering for debugging such modifications, if you also do each of
154
- the following:
155
-
156
- a) Give prominent notice with each copy of the Combined Work that
157
- the Library is used in it and that the Library and its use are
158
- covered by this License.
159
-
160
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
161
- document.
162
-
163
- c) For a Combined Work that displays copyright notices during
164
- execution, include the copyright notice for the Library among
165
- these notices, as well as a reference directing the user to the
166
- copies of the GNU GPL and this license document.
167
-
168
- d) Do one of the following:
169
-
170
- 0) Convey the Minimal Corresponding Source under the terms of this
171
- License, and the Corresponding Application Code in a form
172
- suitable for, and under terms that permit, the user to
173
- recombine or relink the Application with a modified version of
174
- the Linked Version to produce a modified Combined Work, in the
175
- manner specified by section 6 of the GNU GPL for conveying
176
- Corresponding Source.
177
-
178
- 1) Use a suitable shared library mechanism for linking with the
179
- Library. A suitable mechanism is one that (a) uses at run time
180
- a copy of the Library already present on the user's computer
181
- system, and (b) will operate properly with a modified version
182
- of the Library that is interface-compatible with the Linked
183
- Version.
184
-
185
- e) Provide Installation Information, but only if you would otherwise
186
- be required to provide such information under section 6 of the
187
- GNU GPL, and only to the extent that such information is
188
- necessary to install and execute a modified version of the
189
- Combined Work produced by recombining or relinking the
190
- Application with a modified version of the Linked Version. (If
191
- you use option 4d0, the Installation Information must accompany
192
- the Minimal Corresponding Source and Corresponding Application
193
- Code. If you use option 4d1, you must provide the Installation
194
- Information in the manner specified by section 6 of the GNU GPL
195
- for conveying Corresponding Source.)
196
-
197
- 5. Combined Libraries.
198
-
199
- You may place library facilities that are a work based on the
200
- Library side by side in a single library together with other library
201
- facilities that are not Applications and are not covered by this
202
- License, and convey such a combined library under terms of your
203
- choice, if you do both of the following:
204
-
205
- a) Accompany the combined library with a copy of the same work based
206
- on the Library, uncombined with any other library facilities,
207
- conveyed under the terms of this License.
208
-
209
- b) Give prominent notice with the combined library that part of it
210
- is a work based on the Library, and explaining where to find the
211
- accompanying uncombined form of the same work.
212
-
213
- 6. Revised Versions of the GNU Lesser General Public License.
214
-
215
- The Free Software Foundation may publish revised and/or new versions
216
- of the GNU Lesser General Public License from time to time. Such new
217
- versions will be similar in spirit to the present version, but may
218
- differ in detail to address new problems or concerns.
219
-
220
- Each version is given a distinguishing version number. If the
221
- Library as you received it specifies that a certain numbered version
222
- of the GNU Lesser General Public License "or any later version"
223
- applies to it, you have the option of following the terms and
224
- conditions either of that published version or of any later version
225
- published by the Free Software Foundation. If the Library as you
226
- received it does not specify a version number of the GNU Lesser
227
- General Public License, you may choose any version of the GNU Lesser
228
- General Public License ever published by the Free Software Foundation.
229
-
230
- If the Library as you received it specifies that a proxy can decide
231
- whether future versions of the GNU Lesser General Public License shall
232
- apply, that proxy's public statement of acceptance of any version is
233
- permanent authorization for you to choose that version for the
234
- Library.
73
+ Copyright (c) 2009, Will Sargent
74
+ All rights reserved.
75
+
76
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
77
+ following conditions are met:
78
+
79
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
80
+ disclaimer.
81
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
82
+ disclaimer in the documentation and/or other materials provided with the distribution.
83
+ * The names of its contributors may not be used to endorse or promote products derived from this software without
84
+ specific prior written permission.
85
+
86
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
87
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
88
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
89
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
90
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
91
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
92
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile CHANGED
@@ -1,26 +1,6 @@
1
- # -*- ruby -*-
2
- $:.unshift(File.dirname(__FILE__) + "/lib")
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
- require 'rubygems'
5
- require 'hoe'
6
- require 'circuit_breaker'
4
+ RSpec::Core::RakeTask.new(:spec)
7
5
 
8
- hoe = Hoe.spec 'circuit_breaker' do |p|
9
- self.rubyforge_name = 'will_sargent'
10
- developer('Will Sargent', 'will.sargent@gmail.com')
11
-
12
- p.remote_rdoc_dir = '' # Release to root only one project
13
-
14
- p.extra_deps << [ 'rubyist-aasm' ]
15
- p.extra_dev_deps << [ 'rspec' ]
16
- File.open(File.join(File.dirname(__FILE__), 'VERSION'), 'w') do |file|
17
- file.puts CircuitBreaker::VERSION
18
- end
19
- end
20
-
21
- begin
22
- require 'jeweler'
23
- Jeweler::Tasks.new(hoe.spec)
24
- rescue LoadError
25
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
26
- end
6
+ task :default => :spec
@@ -1,76 +1,66 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- Gem::Specification.new do |s|
4
- s.name = %q{circuit_breaker}
5
- s.version = "1.0.0"
6
-
7
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Will Sargent"]
9
- s.date = %q{2009-07-13}
10
- s.description = %q{CircuitBreaker is a relatively simple Ruby mixin that will wrap
11
- a call to a given service in a circuit breaker pattern.
12
-
13
- The circuit starts off "closed" meaning that all calls will go through.
14
- However, consecutive failures are recorded and after a threshold is reached,
15
- the circuit will "trip", setting the circuit into an "open" state.
16
-
17
- In an "open" state, every call to the service will fail by raising
18
- CircuitBrokenException.
19
-
20
- The circuit will remain in an "open" state until the failure timeout has
21
- elapsed.
22
-
23
- After the failure_timeout has elapsed, the circuit will go into
24
- a "half open" state and the call will go through. A failure will
25
- immediately pop the circuit open again, and a success will close the
26
- circuit and reset the failure count.
27
-
28
- require 'circuit_breaker'
29
- class TestService
30
-
31
- include CircuitBreaker
32
-
33
- def call_remote_service() ...
34
-
35
- circuit_method :call_remote_service
36
-
37
- # Optional
38
- circuit_handler do |handler|
39
- handler.logger = Logger.new(STDOUT)
40
- handler.failure_threshold = 5
41
- handler.failure_timeout = 5
42
- end
43
-
44
- # Optional
45
- circuit_handler_class MyCustomCircuitHandler
46
- end}
47
- s.email = ["will.sargent@gmail.com"]
48
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
49
- s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "circuit_breaker.gemspec", "lib/circuit_breaker.rb", "lib/circuit_breaker/circuit_state.rb", "lib/circuit_breaker/circuit_handler.rb", "lib/circuit_breaker/circuit_broken_exception.rb", "spec/unit_spec_helper.rb", "spec/unit/circuit_breaker_spec.rb"]
50
- s.homepage = %q{http://github.com/wsargent/circuit_breaker}
51
- s.rdoc_options = ["--main", "README.txt", "--charset=UTF-8"]
52
- s.require_paths = ["lib"]
53
- s.rubyforge_project = %q{will_sargent}
54
- s.rubygems_version = %q{1.3.4}
55
- s.summary = %q{CircuitBreaker is a relatively simple Ruby mixin that will wrap a call to a given service in a circuit breaker pattern}
56
- s.test_files = ["spec/unit/circuit_breaker_spec.rb", "spec/unit_spec_helper.rb"]
57
-
58
- if s.respond_to? :specification_version then
59
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
60
- s.specification_version = 3
61
-
62
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
63
- s.add_runtime_dependency(%q<rubyist-aasm>, [">= 0"])
64
- s.add_development_dependency(%q<rspec>, [">= 0"])
65
- s.add_development_dependency(%q<hoe>, [">= 2.3.1"])
66
- else
67
- s.add_dependency(%q<rubyist-aasm>, [">= 0"])
68
- s.add_dependency(%q<rspec>, [">= 0"])
69
- s.add_dependency(%q<hoe>, [">= 2.3.1"])
70
- end
71
- else
72
- s.add_dependency(%q<rubyist-aasm>, [">= 0"])
73
- s.add_dependency(%q<rspec>, [">= 0"])
74
- s.add_dependency(%q<hoe>, [">= 2.3.1"])
75
- end
76
- end
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'circuit_breaker/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{circuit_breaker}
7
+ s.version = CircuitBreaker::VERSION
8
+ s.date = %q{2011-01-05}
9
+
10
+ s.authors = ["Will Sargent"]
11
+ s.email = ["will.sargent@gmail.com"]
12
+ s.homepage = %q{http://github.com/wsargent/circuit_breaker}
13
+ s.summary = %q{CircuitBreaker is a relatively simple Ruby mixin that will wrap a call to a given service in a circuit breaker pattern}
14
+ s.description = %q{CircuitBreaker is a relatively simple Ruby mixin that will wrap
15
+ a call to a given service in a circuit breaker pattern.
16
+
17
+ The circuit starts off "closed" meaning that all calls will go through.
18
+ However, consecutive failures are recorded and after a threshold is reached,
19
+ the circuit will "trip", setting the circuit into an "open" state.
20
+
21
+ In an "open" state, every call to the service will fail by raising
22
+ CircuitBrokenException.
23
+
24
+ The circuit will remain in an "open" state until the failure timeout has
25
+ elapsed.
26
+
27
+ After the failure_timeout has elapsed, the circuit will go into
28
+ a "half open" state and the call will go through. A failure will
29
+ immediately pop the circuit open again, and a success will close the
30
+ circuit and reset the failure count.
31
+
32
+ require 'circuit_breaker'
33
+ class TestService
34
+
35
+ include CircuitBreaker
36
+
37
+ def call_remote_service() ...
38
+
39
+ circuit_method :call_remote_service
40
+
41
+ # Optional
42
+ circuit_handler do |handler|
43
+ handler.logger = Logger.new(STDOUT)
44
+ handler.failure_threshold = 5
45
+ handler.failure_timeout = 5
46
+ end
47
+
48
+ # Optional
49
+ circuit_handler_class MyCustomCircuitHandler
50
+ end}
51
+
52
+ s.rubyforge_project = %q{will_sargent}
53
+
54
+ s.files = `git ls-files`.split("\n")
55
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
56
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
57
+ s.require_paths = ["lib"]
58
+
59
+ s.extra_rdoc_files = ["History.txt", "README.txt"]
60
+ s.rdoc_options = ["--main", "README.txt", "--charset=UTF-8"]
61
+
62
+ s.add_runtime_dependency "aasm"
63
+
64
+ s.add_development_dependency "rake"
65
+ s.add_development_dependency "rspec"
66
+ end
@@ -17,6 +17,11 @@
17
17
  # immediately pop the circuit open again, and a success will close the
18
18
  # circuit and reset the failure count.
19
19
  #
20
+ # For services that can take an unmanagable amount of time to respond an
21
+ # invocation timeout threshold is provided. If the service fails to return
22
+ # before the invocation_timeout duration has passed, the circuit will "trip",
23
+ # setting the circuit into an "open" state.
24
+ #
20
25
  # require 'circuit_breaker'
21
26
  # class TestService
22
27
  #
@@ -31,6 +36,7 @@
31
36
  # handler.logger = Logger.new(STDOUT)
32
37
  # handler.failure_threshold = 5
33
38
  # handler.failure_timeout = 5
39
+ # handler.invocation_timeout = 10
34
40
  # end
35
41
  #
36
42
  # # Optional
@@ -42,9 +48,10 @@
42
48
  # Author: Will Sargent <will.sargent@gmail.com>
43
49
  # Many thanks to Devin Mullins
44
50
  #
51
+
52
+ require 'circuit_breaker/version'
53
+
45
54
  module CircuitBreaker
46
- VERSION = '1.0.0'
47
-
48
55
  #
49
56
  # Extends the included class with CircuitBreaker
50
57
  #
@@ -1,10 +1,10 @@
1
1
  class CircuitBreaker::CircuitBrokenException < StandardError
2
2
 
3
- def initialize(msg, circuit_state)
3
+ def initialize(msg, circuit_state = :closed)
4
4
  @circuit_state = circuit_state
5
5
  super(msg)
6
6
  end
7
7
 
8
8
  attr_reader :circuit_state
9
9
 
10
- end
10
+ end
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  #
2
4
  #
3
5
  # CircuitHandler is stateless,
@@ -16,18 +18,25 @@ class CircuitBreaker::CircuitHandler
16
18
  #
17
19
  attr_accessor :failure_timeout
18
20
 
21
+ #
22
+ # The period of time the circuit_method has to return before a timeout exception is thrown.
23
+ #
24
+ attr_accessor :invocation_timeout
25
+
19
26
  #
20
27
  # Optional logger.
21
28
  #
22
29
  attr_accessor :logger
23
30
 
24
- DEFAULT_FAILURE_THRESHOLD = 5
25
- DEFAULT_FAILURE_TIMEOUT = 5
31
+ DEFAULT_FAILURE_THRESHOLD = 5
32
+ DEFAULT_FAILURE_TIMEOUT = 5
33
+ DEFAULT_INVOCATION_TIMEOUT = 30
26
34
 
27
35
  def initialize(logger = nil)
28
36
  @logger = logger
29
37
  @failure_threshold = DEFAULT_FAILURE_THRESHOLD
30
38
  @failure_timeout = DEFAULT_FAILURE_TIMEOUT
39
+ @invocation_timeout = DEFAULT_INVOCATION_TIMEOUT
31
40
  end
32
41
 
33
42
  #
@@ -36,7 +45,7 @@ class CircuitBreaker::CircuitHandler
36
45
  def new_circuit_state
37
46
  ::CircuitBreaker::CircuitState.new
38
47
  end
39
-
48
+
40
49
  #
41
50
  # Handles the method covered by the circuit breaker.
42
51
  #
@@ -47,8 +56,11 @@ class CircuitBreaker::CircuitHandler
47
56
  end
48
57
 
49
58
  begin
50
- out = method[*args]
51
- on_success(circuit_state)
59
+ out = nil
60
+ Timeout.timeout(@invocation_timeout, CircuitBreaker::CircuitBrokenException) do
61
+ out = method[*args]
62
+ on_success(circuit_state)
63
+ end
52
64
  rescue Exception
53
65
  on_failure(circuit_state)
54
66
  raise
@@ -92,7 +104,7 @@ class CircuitBreaker::CircuitHandler
92
104
  end
93
105
 
94
106
  #
95
- # Called when an individual success happens.
107
+ # Called when an individual success happens.
96
108
  #
97
109
  def on_success(circuit_state)
98
110
  @logger.debug("on_success: #{circuit_state.inspect}") if @logger
@@ -113,7 +125,7 @@ class CircuitBreaker::CircuitHandler
113
125
  #
114
126
  def on_failure(circuit_state)
115
127
  @logger.debug("on_failure: circuit_state = #{circuit_state.inspect}") if @logger
116
-
128
+
117
129
  circuit_state.increment_failure_count
118
130
 
119
131
  if is_failure_threshold_reached(circuit_state) || circuit_state.half_open?
@@ -124,12 +136,12 @@ class CircuitBreaker::CircuitHandler
124
136
  end
125
137
 
126
138
  #
127
- # Called when a call is made and the circuit is open. Raises a CircuitBrokenException exception.
139
+ # Called when a call is made and the circuit is open. Raises a CircuitBrokenException exception.
128
140
  #
129
141
  def on_circuit_open(circuit_state)
130
142
  @logger.debug("on_circuit_open: raising for #{circuit_state.inspect}") if @logger
131
-
143
+
132
144
  raise CircuitBreaker::CircuitBrokenException.new("Circuit broken, please wait for timeout", circuit_state)
133
145
  end
134
-
135
- end
146
+
147
+ end
@@ -55,6 +55,6 @@ class CircuitBreaker::CircuitState
55
55
  def reset_failure_count
56
56
  @failure_count = 0
57
57
  end
58
-
58
+
59
59
  end
60
60
 
@@ -0,0 +1,3 @@
1
+ module CircuitBreaker
2
+ VERSION = '1.0.1'
3
+ end
@@ -1,5 +1,4 @@
1
- require File.dirname(__FILE__) + '/../unit_spec_helper'
2
-
1
+ require 'spec_helper'
3
2
  require 'logger'
4
3
 
5
4
  describe CircuitBreaker do
@@ -28,13 +27,18 @@ describe CircuitBreaker do
28
27
  "hello world!"
29
28
  end
30
29
 
31
- def second_method()
32
- raise 'EPIC FAIL'
33
- end
30
+ def second_method()
31
+ raise 'EPIC FAIL'
32
+ end
33
+
34
+ def unresponsive_method
35
+ sleep 1.1
36
+ "unresponsive method returned"
37
+ end
34
38
 
35
39
  # Register this method with the circuit breaker...
36
40
  #
37
- circuit_method :call_external_method, :second_method
41
+ circuit_method :call_external_method, :second_method, :unresponsive_method
38
42
 
39
43
  #
40
44
  # Define what needs to be set for configuration...
@@ -42,7 +46,8 @@ describe CircuitBreaker do
42
46
  circuit_handler do |handler|
43
47
  handler.logger = Logger.new(STDOUT)
44
48
  handler.failure_threshold = 5
45
- handler.failure_timeout = 5
49
+ handler.failure_timeout = 5
50
+ handler.invocation_timeout = 1
46
51
  end
47
52
 
48
53
  end
@@ -72,7 +77,7 @@ describe CircuitBreaker do
72
77
  @test_object.circuit_state.closed?.should == true
73
78
  @test_object.circuit_state.failure_count.should == 1
74
79
  end
75
-
80
+
76
81
  it 'should trip the circuit when too many failures occur' do
77
82
  @test_object.fail!
78
83
 
@@ -103,11 +108,16 @@ describe CircuitBreaker do
103
108
  @test_object.fail!
104
109
 
105
110
  TestClass.circuit_handler.failure_threshold = 0
106
- lambda { @test_object.call_external_method() }.should raise_error
111
+ lambda { @test_object.call_external_method() }.should raise_error
107
112
  @test_object.circuit_state.open?.should == true
108
113
  @test_object.circuit_state.failure_count.should == 1
109
114
  end
110
-
115
+
116
+ it 'should trip the circuit when the method takes too long to return' do
117
+ lambda { @test_object.unresponsive_method }.should raise_error(CircuitBreaker::CircuitBrokenException)
118
+ @test_object.circuit_state.open?.should == true
119
+ end
120
+
111
121
  end
112
122
 
113
123
  describe "when open" do
@@ -182,4 +192,4 @@ describe CircuitBreaker do
182
192
 
183
193
  end
184
194
 
185
- end
195
+ end
@@ -0,0 +1 @@
1
+ require 'circuit_breaker'
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: circuit_breaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ hash: 21
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Will Sargent
@@ -9,39 +15,50 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-07-13 00:00:00 -07:00
13
- default_executable:
18
+ date: 2011-01-05 00:00:00 Z
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
- name: rubyist-aasm
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
21
+ name: aasm
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
23
31
  version: "0"
24
- version:
32
+ type: :runtime
33
+ version_requirements: *id001
25
34
  - !ruby/object:Gem::Dependency
26
- name: rspec
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
35
+ name: rake
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
30
39
  requirements:
31
40
  - - ">="
32
41
  - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
33
45
  version: "0"
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: hoe
37
46
  type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
40
53
  requirements:
41
54
  - - ">="
42
55
  - !ruby/object:Gem::Version
43
- version: 2.3.1
44
- version:
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
45
62
  description: |-
46
63
  CircuitBreaker is a relatively simple Ruby mixin that will wrap
47
64
  a call to a given service in a circuit breaker pattern.
@@ -69,7 +86,7 @@ description: |-
69
86
  def call_remote_service() ...
70
87
 
71
88
  circuit_method :call_remote_service
72
-
89
+
73
90
  # Optional
74
91
  circuit_handler do |handler|
75
92
  handler.logger = Logger.new(STDOUT)
@@ -88,21 +105,22 @@ extensions: []
88
105
 
89
106
  extra_rdoc_files:
90
107
  - History.txt
91
- - Manifest.txt
92
108
  - README.txt
93
109
  files:
110
+ - .gitignore
111
+ - .rspec
112
+ - Gemfile
94
113
  - History.txt
95
- - Manifest.txt
96
114
  - README.txt
97
115
  - Rakefile
98
116
  - circuit_breaker.gemspec
99
117
  - lib/circuit_breaker.rb
100
- - lib/circuit_breaker/circuit_state.rb
101
- - lib/circuit_breaker/circuit_handler.rb
102
118
  - lib/circuit_breaker/circuit_broken_exception.rb
103
- - spec/unit_spec_helper.rb
104
- - spec/unit/circuit_breaker_spec.rb
105
- has_rdoc: true
119
+ - lib/circuit_breaker/circuit_handler.rb
120
+ - lib/circuit_breaker/circuit_state.rb
121
+ - lib/circuit_breaker/version.rb
122
+ - spec/circuit_breaker_spec.rb
123
+ - spec/spec_helper.rb
106
124
  homepage: http://github.com/wsargent/circuit_breaker
107
125
  licenses: []
108
126
 
@@ -114,24 +132,30 @@ rdoc_options:
114
132
  require_paths:
115
133
  - lib
116
134
  required_ruby_version: !ruby/object:Gem::Requirement
135
+ none: false
117
136
  requirements:
118
137
  - - ">="
119
138
  - !ruby/object:Gem::Version
139
+ hash: 3
140
+ segments:
141
+ - 0
120
142
  version: "0"
121
- version:
122
143
  required_rubygems_version: !ruby/object:Gem::Requirement
144
+ none: false
123
145
  requirements:
124
146
  - - ">="
125
147
  - !ruby/object:Gem::Version
148
+ hash: 3
149
+ segments:
150
+ - 0
126
151
  version: "0"
127
- version:
128
152
  requirements: []
129
153
 
130
154
  rubyforge_project: will_sargent
131
- rubygems_version: 1.3.4
155
+ rubygems_version: 1.8.10
132
156
  signing_key:
133
157
  specification_version: 3
134
158
  summary: CircuitBreaker is a relatively simple Ruby mixin that will wrap a call to a given service in a circuit breaker pattern
135
159
  test_files:
136
- - spec/unit/circuit_breaker_spec.rb
137
- - spec/unit_spec_helper.rb
160
+ - spec/circuit_breaker_spec.rb
161
+ - spec/spec_helper.rb
data/Manifest.txt DELETED
@@ -1,11 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.txt
4
- Rakefile
5
- circuit_breaker.gemspec
6
- lib/circuit_breaker.rb
7
- lib/circuit_breaker/circuit_state.rb
8
- lib/circuit_breaker/circuit_handler.rb
9
- lib/circuit_breaker/circuit_broken_exception.rb
10
- spec/unit_spec_helper.rb
11
- spec/unit/circuit_breaker_spec.rb
@@ -1,5 +0,0 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
-
3
- require 'spec'
4
- require 'circuit_breaker'
5
-