circuit_b 1.0 → 1.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/CHANGELOG.md +6 -0
- data/README.md +46 -4
- data/Rakefile +31 -0
- data/circuit_b.gemspec +64 -0
- data/lib/circuit_b/configuration.rb +24 -2
- data/lib/circuit_b/fuse.rb +36 -3
- data/test/unit/circuit_b/test_configuration.rb +4 -4
- data/test/unit/circuit_b/test_fuse.rb +66 -2
- data/test/unit/test_circuit_b.rb +8 -2
- metadata +36 -13
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -38,9 +38,11 @@ Configuration
|
|
38
38
|
# Configure the default fuse configuration that will be
|
39
39
|
# used as the basis when you add your custom fuses. You
|
40
40
|
# can specify only the parameters you want to override then.
|
41
|
-
|
41
|
+
c.default_fuse_config = {
|
42
|
+
:on_break => [ :rails_log, lambda { do_something } ],
|
42
43
|
:allowed_failures => 2,
|
43
44
|
:cool_off_period => 3 # seconds
|
45
|
+
:timeout => 3 # seconds, defaults to 5
|
44
46
|
}
|
45
47
|
|
46
48
|
# Adds a fuse named "mail" that is configured to tolerate
|
@@ -48,7 +50,7 @@ Configuration
|
|
48
50
|
# of 60 seconds it will close again. During the cool-off
|
49
51
|
# time it will be raising FastFailure's without even
|
50
52
|
# executing the code to protect the system from overload.
|
51
|
-
c.
|
53
|
+
c.fuse "mail", :allowed_failures => 5, :cool_off_period => 60
|
52
54
|
|
53
55
|
end
|
54
56
|
|
@@ -68,6 +70,48 @@ the fuse state that you can use:
|
|
68
70
|
and acts like a simple IPC.
|
69
71
|
|
70
72
|
|
73
|
+
Acting on Fuse Breaks
|
74
|
+
=====================
|
75
|
+
|
76
|
+
When the ciruit is broken, meaning that your wrapped code has produced
|
77
|
+
so many errors that we had to isolate it, the fuse opens and starts to
|
78
|
+
fail fast. You may want to act in one way or another when it happens.
|
79
|
+
There's a fuse configuration option `on_break` that accepts one or more
|
80
|
+
elements describing what you want to do.
|
81
|
+
|
82
|
+
*Logging.* One of the common steps is to log the event. There's a
|
83
|
+
standard logging feature (`:rails_log`) that writes a message to the
|
84
|
+
default Rails log. If you don't use Rails, you can use the next feature
|
85
|
+
to take care of your logging.
|
86
|
+
|
87
|
+
config.fuse "test", :on_break => :rails_log
|
88
|
+
|
89
|
+
*Handling.* If you want to handle the event in some custom way, you
|
90
|
+
can provide a `Proc` that will be executed upon event. One common case
|
91
|
+
is to write to the log.
|
92
|
+
|
93
|
+
config.fuse "test", :on_break => lambda { |fuse| puts "Fuse #{fuse.name} has just broke the circuit" }
|
94
|
+
|
95
|
+
To specify more than one handler, you can use an array:
|
96
|
+
|
97
|
+
config.fuse "test", :on_break => [ :rails_log, lambda { ... }, lambda { ... } ]
|
98
|
+
|
99
|
+
|
100
|
+
Code execution timeouts
|
101
|
+
=======================
|
102
|
+
|
103
|
+
To protect your code from executing for too long, fuses in CircuitB can
|
104
|
+
execute it wrapped into the timeout statements. All you have to do is
|
105
|
+
to configure a fuse to use timeouts logic, like this (to allow 5 second for
|
106
|
+
wrapped code execution):
|
107
|
+
|
108
|
+
config.fuse "test", :timeout => 2
|
109
|
+
|
110
|
+
To disable timeouts (which isn't a great idea), use `:timeout => false`.
|
111
|
+
|
112
|
+
By default, all fuses use 5 second timeouts.
|
113
|
+
|
114
|
+
|
71
115
|
Usage
|
72
116
|
=====
|
73
117
|
|
@@ -89,9 +133,7 @@ it all in one place.
|
|
89
133
|
To Do
|
90
134
|
=====
|
91
135
|
|
92
|
-
* notifications and logging
|
93
136
|
* half-open state to open back faster if the problem still exists
|
94
|
-
* internal code block execution timeout support
|
95
137
|
* incrementing cool-off period on recurring errors (in half-open state)
|
96
138
|
* CouchDB storage
|
97
139
|
* Memcached storage
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
$:.unshift(File.dirname(__FILE__) + '/lib')
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "circuit_b"
|
10
|
+
gem.version = "1.1"
|
11
|
+
gem.summary = %Q{Distributed circuit breaker}
|
12
|
+
gem.description = %Q{Classic circuit breaker to protect resources from being accessed over and over while in pain.}
|
13
|
+
gem.email = "spyromus@noizeramp.com"
|
14
|
+
gem.homepage = "http://github.com/alg/circuit_b"
|
15
|
+
gem.authors = ["Aleksey Gureiev"]
|
16
|
+
|
17
|
+
gem.add_development_dependency 'shoulda', '>= 2.10.3'
|
18
|
+
gem.add_development_dependency 'timecop', '>= 0.3.4'
|
19
|
+
end
|
20
|
+
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
Dir['gem_tasks/**/*.rake'].each { |rake| load rake }
|
27
|
+
|
28
|
+
task :default => [:check_dependencies, :test]
|
29
|
+
|
30
|
+
require 'rake/clean'
|
31
|
+
CLEAN.include %w(**/*.{log,pyc})
|
data/circuit_b.gemspec
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{circuit_b}
|
8
|
+
s.version = "1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Aleksey Gureiev"]
|
12
|
+
s.date = %q{2010-02-04}
|
13
|
+
s.description = %q{Classic circuit breaker to protect resources from being accessed over and over while in pain.}
|
14
|
+
s.email = %q{spyromus@noizeramp.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"CHANGELOG.md",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.md",
|
22
|
+
"Rakefile",
|
23
|
+
"circuit_b.gemspec",
|
24
|
+
"lib/circuit_b.rb",
|
25
|
+
"lib/circuit_b/configuration.rb",
|
26
|
+
"lib/circuit_b/fuse.rb",
|
27
|
+
"lib/circuit_b/storage.rb",
|
28
|
+
"lib/circuit_b/storage/base.rb",
|
29
|
+
"lib/circuit_b/storage/memory.rb",
|
30
|
+
"lib/circuit_b/storage/redis.rb",
|
31
|
+
"test/test_helper.rb",
|
32
|
+
"test/unit/circuit_b/test_configuration.rb",
|
33
|
+
"test/unit/circuit_b/test_fuse.rb",
|
34
|
+
"test/unit/test_circuit_b.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/alg/circuit_b}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.5}
|
40
|
+
s.summary = %q{Distributed circuit breaker}
|
41
|
+
s.test_files = [
|
42
|
+
"test/test_helper.rb",
|
43
|
+
"test/unit/circuit_b/test_configuration.rb",
|
44
|
+
"test/unit/circuit_b/test_fuse.rb",
|
45
|
+
"test/unit/test_circuit_b.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_development_dependency(%q<shoulda>, [">= 2.10.3"])
|
54
|
+
s.add_development_dependency(%q<timecop>, [">= 0.3.4"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.3"])
|
57
|
+
s.add_dependency(%q<timecop>, [">= 0.3.4"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.3"])
|
61
|
+
s.add_dependency(%q<timecop>, [">= 0.3.4"])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -5,6 +5,8 @@ module CircuitB
|
|
5
5
|
class Configuration
|
6
6
|
|
7
7
|
DEFAULT_CONFIG = {
|
8
|
+
:log => true,
|
9
|
+
:timeout => 5, # seconds
|
8
10
|
:allowed_failures => 5,
|
9
11
|
:cool_off_period => 10 # seconds
|
10
12
|
}
|
@@ -19,14 +21,34 @@ module CircuitB
|
|
19
21
|
@fuses = {}
|
20
22
|
end
|
21
23
|
|
24
|
+
# Sets the default fuse configuration. This configuration will be used
|
25
|
+
# as the basis for all fuses. You can override the values by providing
|
26
|
+
# your own when calling #fuse.
|
27
|
+
#
|
28
|
+
# CircuitB.configure do |c|
|
29
|
+
# c.default_fuse_config = {
|
30
|
+
# :on_break => [ :rails_log, lambda { do_something } ],
|
31
|
+
# :allowed_failures => 2,
|
32
|
+
# :cool_off_period => 3 # seconds
|
33
|
+
# }
|
34
|
+
# end
|
22
35
|
def default_fuse_config=(config)
|
23
36
|
@default_fuse_config = DEFAULT_CONFIG.merge(config)
|
24
37
|
end
|
25
38
|
|
26
|
-
|
39
|
+
# Adds a fuse with a given name and custom config.
|
40
|
+
# If the fuse with the same name is already there, the RuntimeError is raised.
|
41
|
+
# The values of the provided configuration are used to override
|
42
|
+
# the default configuration that can be set with #default_fuse_config.
|
43
|
+
#
|
44
|
+
# CircuitB.configure do |c|
|
45
|
+
# c.fuse "directory-auth", :on_break => lambda { notify_hoptoad(...) }, :allowed_failures => 5
|
46
|
+
# c.fuse "image-resizing", :allowed_failures => 2, :cool_off_period => 30
|
47
|
+
# end
|
48
|
+
def fuse(name, config = {})
|
27
49
|
raise "Fuse with this name is already registered" if @fuses.include?(name)
|
28
50
|
|
29
|
-
config =
|
51
|
+
config = @default_fuse_config.merge(config || {})
|
30
52
|
@fuses[name] = CircuitB::Fuse.new(name, state_storage, config)
|
31
53
|
end
|
32
54
|
|
data/lib/circuit_b/fuse.rb
CHANGED
@@ -3,7 +3,16 @@ require 'circuit_b/storage/base'
|
|
3
3
|
module CircuitB
|
4
4
|
class Fuse
|
5
5
|
|
6
|
-
|
6
|
+
# Maximum time the handler is allowed to execute
|
7
|
+
DEFAULT_BREAK_HANDLER_TIMEOUT = 5
|
8
|
+
|
9
|
+
# Standard handlers that can be refered by their names
|
10
|
+
STANDARD_HANDLERS = {
|
11
|
+
:rails_log => lambda { |fuse| RAILS_DEFAULT_LOGGER.error("CircuitB: Fuse '#{fuse.name}' has broken") }
|
12
|
+
}
|
13
|
+
|
14
|
+
attr_reader :name, :config
|
15
|
+
attr_accessor :break_handler_timeout
|
7
16
|
|
8
17
|
def initialize(name, state_storage, config)
|
9
18
|
raise "Name must be specified" if name.nil?
|
@@ -14,6 +23,8 @@ module CircuitB
|
|
14
23
|
@name = name
|
15
24
|
@state_storage = state_storage
|
16
25
|
@config = config
|
26
|
+
|
27
|
+
@break_handler_timeout = DEFAULT_BREAK_HANDLER_TIMEOUT
|
17
28
|
end
|
18
29
|
|
19
30
|
def wrap(&block)
|
@@ -21,10 +32,14 @@ module CircuitB
|
|
21
32
|
raise CircuitB::FastFailure if open?
|
22
33
|
|
23
34
|
begin
|
24
|
-
|
35
|
+
if @config[:timeout] && @config[:timeout].to_f > 0
|
36
|
+
Timeout::timeout(@config[:timeout].to_f) { block.call }
|
37
|
+
else
|
38
|
+
block.call
|
39
|
+
end
|
25
40
|
|
26
41
|
put(:failures, 0)
|
27
|
-
rescue => e
|
42
|
+
rescue Exception => e
|
28
43
|
# Save the time of the last failure
|
29
44
|
put(:last_failure_at, Time.now.to_i)
|
30
45
|
|
@@ -57,6 +72,24 @@ module CircuitB
|
|
57
72
|
# Open the fuse
|
58
73
|
def open
|
59
74
|
put(:state, :open)
|
75
|
+
|
76
|
+
if config[:on_break]
|
77
|
+
require 'timeout'
|
78
|
+
|
79
|
+
handlers = [ config[:on_break] ].flatten.map { |handler| (handler.is_a?(Symbol) ? STANDARD_HANDLERS[handler] : handler) }.compact
|
80
|
+
|
81
|
+
handlers.each do |handler|
|
82
|
+
begin
|
83
|
+
Timeout::timeout(@break_handler_timeout) {
|
84
|
+
handler.call(self)
|
85
|
+
}
|
86
|
+
rescue Timeout::Error
|
87
|
+
# We ignore handler timeouts
|
88
|
+
rescue
|
89
|
+
# We ignore handler errors
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
60
93
|
end
|
61
94
|
|
62
95
|
def get(field)
|
@@ -19,18 +19,18 @@ class CircuitB::TestConfiguration < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
should "add a named fuse with default configuration" do
|
22
|
-
@config.
|
22
|
+
@config.fuse "fuse_name"
|
23
23
|
assert_equal 1, @config.fuses.size
|
24
24
|
end
|
25
25
|
|
26
26
|
should "add a named fuse with custom configuration" do
|
27
|
-
@config.
|
27
|
+
@config.fuse "fuse_name", :allowed_failures => 5
|
28
28
|
end
|
29
29
|
|
30
30
|
should "disallow adding fuses with the same name" do
|
31
|
-
@config.
|
31
|
+
@config.fuse "fuse_name"
|
32
32
|
begin
|
33
|
-
@config.
|
33
|
+
@config.fuse "fuse_name"
|
34
34
|
fail "should raise an exception"
|
35
35
|
rescue
|
36
36
|
# Exception is expected
|
@@ -43,7 +43,7 @@ class CircuitB::TestFuse < Test::Unit::TestCase
|
|
43
43
|
|
44
44
|
context "operation" do
|
45
45
|
setup do
|
46
|
-
@fuse =
|
46
|
+
@fuse = memory_fuse
|
47
47
|
end
|
48
48
|
|
49
49
|
should "open when the allowed failures reached" do
|
@@ -53,7 +53,7 @@ class CircuitB::TestFuse < Test::Unit::TestCase
|
|
53
53
|
end
|
54
54
|
|
55
55
|
should "reset the failures counter when the attempt succeeds" do
|
56
|
-
@fuse =
|
56
|
+
@fuse = memory_fuse(:allowed_failures => 2)
|
57
57
|
|
58
58
|
do_failure(@fuse)
|
59
59
|
assert_equal 1, @fuse.failures
|
@@ -109,6 +109,65 @@ class CircuitB::TestFuse < Test::Unit::TestCase
|
|
109
109
|
assert !@fuse.open?
|
110
110
|
end
|
111
111
|
end
|
112
|
+
|
113
|
+
context "on-break handlers" do
|
114
|
+
should "call single handler" do
|
115
|
+
handler_fuse = nil
|
116
|
+
handler = lambda { |fuse| handler_fuse = fuse }
|
117
|
+
@fuse = memory_fuse(:on_break => handler)
|
118
|
+
|
119
|
+
do_failure(@fuse)
|
120
|
+
|
121
|
+
assert_equal @fuse, handler_fuse
|
122
|
+
end
|
123
|
+
|
124
|
+
should "call all of handlers" do
|
125
|
+
handler_calls = 0
|
126
|
+
handler = lambda { |fuse| handler_calls += 1 }
|
127
|
+
@fuse = memory_fuse(:on_break => [ handler, handler ])
|
128
|
+
|
129
|
+
do_failure(@fuse)
|
130
|
+
|
131
|
+
assert_equal 2, handler_calls
|
132
|
+
end
|
133
|
+
|
134
|
+
should "ignore failures of handlers" do
|
135
|
+
handler_calls = 0
|
136
|
+
handler = lambda { |fuse| handler_calls += 1 }
|
137
|
+
failing_handler = lambda { |fuse| raise "Handling error" }
|
138
|
+
@fuse = memory_fuse(:on_break => [ failing_handler, handler ])
|
139
|
+
|
140
|
+
do_failure(@fuse)
|
141
|
+
|
142
|
+
assert_equal 1, handler_calls
|
143
|
+
end
|
144
|
+
|
145
|
+
should "interrupt long handlers (no more than 5 seconds)" do
|
146
|
+
handler_calls = 0
|
147
|
+
long_handler = lambda { |fuse| sleep 10; handler_calls += 1 }
|
148
|
+
short_handler = lambda { |fuse| handler_calls += 1 }
|
149
|
+
@fuse = memory_fuse(:on_break => [ long_handler, short_handler ])
|
150
|
+
@fuse.break_handler_timeout = 0.1
|
151
|
+
|
152
|
+
do_failure(@fuse)
|
153
|
+
|
154
|
+
assert_equal 1, handler_calls
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "execution timeouts" do
|
159
|
+
should "fail long tasks" do
|
160
|
+
@fuse = memory_fuse(:timeout => 0.1)
|
161
|
+
begin
|
162
|
+
@fuse.wrap do
|
163
|
+
sleep 0.2
|
164
|
+
end
|
165
|
+
fail "Timeout::Error should be thrown"
|
166
|
+
rescue Timeout::Error
|
167
|
+
assert @fuse.open?
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
112
171
|
end
|
113
172
|
|
114
173
|
def do_failure(fuse, rethrow = false)
|
@@ -120,4 +179,9 @@ class CircuitB::TestFuse < Test::Unit::TestCase
|
|
120
179
|
raise e if rethrow
|
121
180
|
end
|
122
181
|
end
|
182
|
+
|
183
|
+
def memory_fuse(options = {})
|
184
|
+
options = { :allowed_failures => 1, :cool_off_period => 60 }.merge(options)
|
185
|
+
CircuitB::Fuse.new("name", CircuitB::Storage::Memory.new, options)
|
186
|
+
end
|
123
187
|
end
|
data/test/unit/test_circuit_b.rb
CHANGED
@@ -15,7 +15,7 @@ class TestCircuitB < Test::Unit::TestCase
|
|
15
15
|
:cool_off_period => 3 # seconds
|
16
16
|
}
|
17
17
|
|
18
|
-
config.
|
18
|
+
config.fuse("mail", {
|
19
19
|
:allowed_failures => 5,
|
20
20
|
:cool_off_period => 10 # seconds
|
21
21
|
})
|
@@ -30,10 +30,16 @@ class TestCircuitB < Test::Unit::TestCase
|
|
30
30
|
|
31
31
|
context "using fuses to protect code" do
|
32
32
|
setup do
|
33
|
+
begin
|
34
|
+
CircuitB::Storage::Redis.new.get('dummy', 'field')
|
35
|
+
rescue Errno::ECONNREFUSED => e
|
36
|
+
fail "Please start Redis on default port"
|
37
|
+
end
|
38
|
+
|
33
39
|
CircuitB.reset_configuration
|
34
40
|
CircuitB.configure do |c|
|
35
41
|
c.state_storage = CircuitB::Storage::Redis.new
|
36
|
-
c.
|
42
|
+
c.fuse "fuse_name", :allowed_failures => 1, :cool_off_period => 10
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: circuit_b
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "1.
|
4
|
+
version: "1.1"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksey Gureiev
|
@@ -9,10 +9,29 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-02-04 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.10.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: timecop
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.4
|
34
|
+
version:
|
16
35
|
description: Classic circuit breaker to protect resources from being accessed over and over while in pain.
|
17
36
|
email: spyromus@noizeramp.com
|
18
37
|
executables: []
|
@@ -20,30 +39,31 @@ executables: []
|
|
20
39
|
extensions: []
|
21
40
|
|
22
41
|
extra_rdoc_files:
|
23
|
-
- MIT-LICENSE
|
24
42
|
- README.md
|
25
43
|
files:
|
44
|
+
- CHANGELOG.md
|
45
|
+
- MIT-LICENSE
|
46
|
+
- README.md
|
47
|
+
- Rakefile
|
48
|
+
- circuit_b.gemspec
|
49
|
+
- lib/circuit_b.rb
|
26
50
|
- lib/circuit_b/configuration.rb
|
27
51
|
- lib/circuit_b/fuse.rb
|
52
|
+
- lib/circuit_b/storage.rb
|
28
53
|
- lib/circuit_b/storage/base.rb
|
29
54
|
- lib/circuit_b/storage/memory.rb
|
30
55
|
- lib/circuit_b/storage/redis.rb
|
31
|
-
- lib/circuit_b/storage.rb
|
32
|
-
- lib/circuit_b.rb
|
33
56
|
- test/test_helper.rb
|
34
57
|
- test/unit/circuit_b/test_configuration.rb
|
35
58
|
- test/unit/circuit_b/test_fuse.rb
|
36
59
|
- test/unit/test_circuit_b.rb
|
37
|
-
- MIT-LICENSE
|
38
|
-
- README.md
|
39
60
|
has_rdoc: true
|
40
61
|
homepage: http://github.com/alg/circuit_b
|
41
62
|
licenses: []
|
42
63
|
|
43
64
|
post_install_message:
|
44
65
|
rdoc_options:
|
45
|
-
- --
|
46
|
-
- CircuitB - Distributed circuit breaker
|
66
|
+
- --charset=UTF-8
|
47
67
|
require_paths:
|
48
68
|
- lib
|
49
69
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -65,5 +85,8 @@ rubygems_version: 1.3.5
|
|
65
85
|
signing_key:
|
66
86
|
specification_version: 3
|
67
87
|
summary: Distributed circuit breaker
|
68
|
-
test_files:
|
69
|
-
|
88
|
+
test_files:
|
89
|
+
- test/test_helper.rb
|
90
|
+
- test/unit/circuit_b/test_configuration.rb
|
91
|
+
- test/unit/circuit_b/test_fuse.rb
|
92
|
+
- test/unit/test_circuit_b.rb
|