supervision 0.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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +22 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +8 -0
- data/lib/supervision/atomic.rb +41 -0
- data/lib/supervision/circuit_breaker.rb +89 -0
- data/lib/supervision/circuit_control.rb +182 -0
- data/lib/supervision/circuit_monitor.rb +13 -0
- data/lib/supervision/circuit_system.rb +16 -0
- data/lib/supervision/configuration.rb +73 -0
- data/lib/supervision/factory.rb +7 -0
- data/lib/supervision/registry.rb +69 -0
- data/lib/supervision/time_dsl.rb +36 -0
- data/lib/supervision/version.rb +5 -0
- data/lib/supervision.rb +67 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/unit/atomic_spec.rb +30 -0
- data/spec/unit/circuit_breaker_spec.rb +102 -0
- data/spec/unit/circuit_control_spec.rb +72 -0
- data/spec/unit/circuit_monitor_spec.rb +6 -0
- data/spec/unit/configuration_spec.rb +14 -0
- data/spec/unit/initialize_spec.rb +55 -0
- data/spec/unit/registry_spec.rb +30 -0
- data/spec/unit/time_dsl_spec.rb +31 -0
- data/supervision.gemspec +23 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- metadata +117 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Supervision
|
4
|
+
# A class responsible for registering/unregistering circuits
|
5
|
+
class Registry
|
6
|
+
|
7
|
+
# Initialize a Registry
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
def initialize
|
11
|
+
@lock = Mutex.new
|
12
|
+
@map = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Register a circuit
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def []=(name, circuit)
|
19
|
+
unless circuit.is_a?(CircuitBreaker)
|
20
|
+
raise TypeError, 'not a circuit'
|
21
|
+
end
|
22
|
+
@lock.synchronize do
|
23
|
+
@map[name.to_sym] = circuit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retrieve a circuit by name
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def [](name)
|
31
|
+
@lock.synchronize do
|
32
|
+
@map[name.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Remove from registry
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def delete(name)
|
40
|
+
@lock.synchronize do
|
41
|
+
@map.delete name.to_sym
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :register, :[]=
|
46
|
+
alias_method :get, :[]
|
47
|
+
alias_method :unregister, :delete
|
48
|
+
|
49
|
+
# Check if circuit is in registry
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
def registered?(name)
|
53
|
+
names.include?(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def names
|
57
|
+
@lock.synchronize { @map.keys }
|
58
|
+
end
|
59
|
+
|
60
|
+
def clear
|
61
|
+
hash = nil
|
62
|
+
@lock.synchronize do
|
63
|
+
hash = @map.dup
|
64
|
+
@map.clear
|
65
|
+
end
|
66
|
+
hash
|
67
|
+
end
|
68
|
+
end # Registry
|
69
|
+
end # Supervision
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Supervision
|
4
|
+
# A mixin to define time related helpers
|
5
|
+
module TimeDSL
|
6
|
+
def millisecond
|
7
|
+
self / 1000.0
|
8
|
+
end
|
9
|
+
alias_method :milliseconds, :millisecond
|
10
|
+
alias_method :milli , :millisecond
|
11
|
+
alias_method :millis , :millisecond
|
12
|
+
|
13
|
+
def second
|
14
|
+
self * 1
|
15
|
+
end
|
16
|
+
alias_method :seconds, :second
|
17
|
+
alias_method :sec , :second
|
18
|
+
alias_method :secs , :second
|
19
|
+
|
20
|
+
def minute
|
21
|
+
self * 60
|
22
|
+
end
|
23
|
+
alias_method :minutes, :minute
|
24
|
+
alias_method :min , :minute
|
25
|
+
alias_method :mins , :minute
|
26
|
+
|
27
|
+
def hour
|
28
|
+
self * 3600
|
29
|
+
end
|
30
|
+
alias_method :hours, :hour
|
31
|
+
end # TimeDSL
|
32
|
+
end # Supervision
|
33
|
+
|
34
|
+
unless Numeric.method_defined?(:second)
|
35
|
+
Numeric.send(:include, Supervision::TimeDSL)
|
36
|
+
end
|
data/lib/supervision.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "thread"
|
4
|
+
require "timeout"
|
5
|
+
require "finite_machine"
|
6
|
+
|
7
|
+
require "supervision/version"
|
8
|
+
require "supervision/atomic"
|
9
|
+
require "supervision/time_dsl"
|
10
|
+
require "supervision/configuration"
|
11
|
+
require "supervision/registry"
|
12
|
+
require "supervision/circuit_control"
|
13
|
+
require "supervision/circuit_breaker"
|
14
|
+
require "supervision/circuit_system"
|
15
|
+
require "supervision/circuit_monitor"
|
16
|
+
|
17
|
+
module Supervision
|
18
|
+
# Generic error
|
19
|
+
SupervisionError = Class.new(::StandardError)
|
20
|
+
|
21
|
+
# Raised when circuit opens
|
22
|
+
CircuitBreakerOpenError = Class.new(SupervisionError)
|
23
|
+
|
24
|
+
TypeError = Class.new(SupervisionError)
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def included(base)
|
28
|
+
base.send :extend, ClassMethods
|
29
|
+
end
|
30
|
+
|
31
|
+
def configuration
|
32
|
+
@configuration ||= Configuration.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def init
|
36
|
+
@circuit_system = CircuitSystem.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def circuit_system
|
40
|
+
Thread.current[:supervision_circuit_system] ||= @circuit_system
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create a new circuit breaker
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def new(name = nil, options = {}, &block)
|
47
|
+
name ? supervise_as(name, options, &block) : supervise(options, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module ClassMethods
|
52
|
+
def supervise(options = {}, &block)
|
53
|
+
CircuitBreaker.new(options, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def supervise_as(name, options = {}, &block)
|
57
|
+
circuit = supervise(options, &block)
|
58
|
+
Supervision.circuit_system[name] = circuit
|
59
|
+
send(:define_method, name) { |*args| circuit.call(args) }
|
60
|
+
circuit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
extend ClassMethods
|
65
|
+
end # Supervision
|
66
|
+
|
67
|
+
Supervision.init
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'supervision'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Helpers
|
7
|
+
def wait_for(duration = nil)
|
8
|
+
Timeout.timeout 1 do
|
9
|
+
sleep(duration || 0.01) until yield
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
config.filter_run :focus
|
18
|
+
config.order = 'random'
|
19
|
+
config.include Helpers
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision::Atomic do
|
6
|
+
|
7
|
+
let(:object) { described_class }
|
8
|
+
|
9
|
+
it "sets the value to nil" do
|
10
|
+
atomic = object.new
|
11
|
+
expect(atomic.value).to eql(nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "sets the value" do
|
15
|
+
atomic = object.new(1)
|
16
|
+
expect(atomic.value).to eql(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "set value" do
|
20
|
+
atomic = object.new
|
21
|
+
atomic.value = 1000
|
22
|
+
expect(atomic.value).to eql(1000)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "updates current value" do
|
26
|
+
atomic = object.new(1000)
|
27
|
+
new_value = atomic.update { |v| v + 1 }
|
28
|
+
expect(new_value).to eql(1001)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision::CircuitBreaker do
|
6
|
+
|
7
|
+
let(:dangerous_call_timeout) { sleep 1 }
|
8
|
+
|
9
|
+
let(:dangerous_call_error) { raise StandardError }
|
10
|
+
|
11
|
+
let(:safe_call) { 'value' }
|
12
|
+
|
13
|
+
let(:object) { described_class }
|
14
|
+
|
15
|
+
|
16
|
+
context 'when closed' do
|
17
|
+
it "successfully calls the method" do
|
18
|
+
circuit = object.new call_timeout: 1.milli do |arg|
|
19
|
+
arg == :danger ? dangerouse_call_error : safe_call
|
20
|
+
end
|
21
|
+
expect(circuit.call(:safe)).to eql(safe_call)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "increments a failure counter for exceptions" do
|
25
|
+
circuit = object.new call_timeout: 1.milli do
|
26
|
+
arg == :danger ? dangerouse_call_error : safe_call
|
27
|
+
end
|
28
|
+
circuit.call(:danger)
|
29
|
+
expect(circuit.control.failure_count).to eql(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "increments a failure counter for calls exceeding :call_timeout" do
|
33
|
+
circuit = object.new call_timeout: 1.milli do
|
34
|
+
dangerous_call_timeout
|
35
|
+
end
|
36
|
+
circuit.call
|
37
|
+
expect(circuit.control.failure_count).to eql(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when open' do
|
42
|
+
it "fails all calls with a CircuitBreakerOpenError" do
|
43
|
+
circuit = object.new max_failures: 2, reset_timeout: 1.sec do
|
44
|
+
dangerous_call_error
|
45
|
+
end
|
46
|
+
circuit.call
|
47
|
+
circuit.call
|
48
|
+
expect { circuit.call }.to raise_error(Supervision::CircuitBreakerOpenError)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "enters a :half_open state after the :reset_timeout" do
|
52
|
+
circuit = object.new reset_timeout: 0.1.sec, max_failures: 0 do
|
53
|
+
dangerous_call_error
|
54
|
+
end
|
55
|
+
expect { circuit.call }.to raise_error(Supervision::CircuitBreakerOpenError)
|
56
|
+
expect(circuit.control.current).to eq(:open)
|
57
|
+
sleep 0.2
|
58
|
+
expect(circuit.control.current).to eq(:half_open)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when half open' do
|
63
|
+
it "resets the breaker back to :closed state on successful call" do
|
64
|
+
circuit = object.new reset_timeout: 100.milli, max_failures: 0 do |arg|
|
65
|
+
arg == :danger ? dangerous_call_error : safe_call
|
66
|
+
end
|
67
|
+
expect {
|
68
|
+
circuit.call(:danger)
|
69
|
+
}.to raise_error(Supervision::CircuitBreakerOpenError)
|
70
|
+
expect(circuit.control.current).to eql(:open)
|
71
|
+
sleep 0.2
|
72
|
+
expect(circuit.control.current).to eql(:half_open)
|
73
|
+
circuit.call(:safe)
|
74
|
+
expect(circuit.control.current).to eql(:closed)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when with callback' do
|
79
|
+
it "notifies about successful call" do
|
80
|
+
callbacks = []
|
81
|
+
circuit = object.new do safe_call end
|
82
|
+
circuit.on_success { callbacks << 'on_success' }
|
83
|
+
circuit.call
|
84
|
+
expect(callbacks).to eql(["on_success"])
|
85
|
+
end
|
86
|
+
|
87
|
+
it "notifies about failed call" do
|
88
|
+
callbacks = []
|
89
|
+
circuit = object.new do dangerous_call_error end
|
90
|
+
circuit.on_failure { callbacks << 'on_failure'}
|
91
|
+
circuit.before { callbacks << 'before'}
|
92
|
+
circuit.call
|
93
|
+
expect(callbacks).to eql(['before', 'on_failure'])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "fails fast with unknown config option" do
|
98
|
+
expect {
|
99
|
+
object.new max_fail: 2 do safe_call end
|
100
|
+
}.to raise_error(ArgumentError)
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision::CircuitControl do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:max_failures) { 1 }
|
9
|
+
|
10
|
+
let(:reset_timeout) { 0.1.sec }
|
11
|
+
|
12
|
+
subject(:control) {
|
13
|
+
object.new max_failures: max_failures,
|
14
|
+
reset_timeout: reset_timeout
|
15
|
+
}
|
16
|
+
|
17
|
+
context 'when closed' do
|
18
|
+
it "resets the failure count on success" do
|
19
|
+
expect(control.failure_count).to eql(0)
|
20
|
+
expect(control.fsm.current).to eql(:closed)
|
21
|
+
control.record_failure
|
22
|
+
expect(control.failure_count).to eql(1)
|
23
|
+
control.reset_failure
|
24
|
+
expect(control.failure_count).to eql(0)
|
25
|
+
expect(control.fsm.current).to eql(:closed)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "increments failure count on exceptions and trips the wire" do
|
29
|
+
expect(control.failure_count).to eql(0)
|
30
|
+
expect(control.fsm.current).to eql(:closed)
|
31
|
+
|
32
|
+
control.handle
|
33
|
+
expect(control.failure_count).to eql(1)
|
34
|
+
expect(control.fsm.current).to eql(:closed)
|
35
|
+
|
36
|
+
expect{ control.handle }.to raise_error(Supervision::CircuitBreakerOpenError)
|
37
|
+
expect(control.failure_count).to eql(2)
|
38
|
+
expect(control.fsm.current).to eql(:open)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when open' do
|
43
|
+
it "fails all calls fast with CircuitBreakerOpenError" do
|
44
|
+
control.fsm.state = :open
|
45
|
+
expect { control.handle }.to raise_error(Supervision::CircuitBreakerOpenError)
|
46
|
+
expect(control.fsm.current).to eql(:open)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "enters :half_open state after the configured :reset_timeout" do
|
50
|
+
control.record_failure
|
51
|
+
expect{ control.handle }.to raise_error(Supervision::CircuitBreakerOpenError)
|
52
|
+
sleep 0.2
|
53
|
+
expect(control.fsm.current).to eql(:half_open)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when half open' do
|
58
|
+
before { control.fsm.state = :half_open }
|
59
|
+
|
60
|
+
it "resets the breaker back to :closed state on successful call" do
|
61
|
+
control.record_success
|
62
|
+
expect(control.fsm.current).to eql(:closed)
|
63
|
+
expect(control.failure_count).to eql(0)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "trips the breaker back to :open state on failed call" do
|
67
|
+
expect { control.handle }.to raise_error(Supervision::CircuitBreakerOpenError)
|
68
|
+
expect(control.failure_count).to eql(1)
|
69
|
+
expect(control.fsm.current).to eql(:open)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision::Configuration do
|
6
|
+
|
7
|
+
subject(:config) { described_class.new }
|
8
|
+
|
9
|
+
it { expect(config.max_failures).to eql(5) }
|
10
|
+
|
11
|
+
it { expect(config.call_timeout).to eql(0.01) }
|
12
|
+
|
13
|
+
it { expect(config.reset_timeout).to eql(0.1) }
|
14
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision do
|
6
|
+
|
7
|
+
context "when used as instance" do
|
8
|
+
it "permits options configuration" do
|
9
|
+
supervision = Supervision.new { }
|
10
|
+
supervision.configure do
|
11
|
+
call_timeout 1.sec
|
12
|
+
max_failures 10
|
13
|
+
end
|
14
|
+
expect(supervision.control.max_failures).to eql(10)
|
15
|
+
expect(supervision.control.call_timeout).to eql(1.sec)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "allows to supervise call" do
|
19
|
+
called = []
|
20
|
+
supervision = Supervision.supervise { called << 'method_call'}
|
21
|
+
supervision.call
|
22
|
+
expect(called).to eql(['method_call'])
|
23
|
+
end
|
24
|
+
|
25
|
+
it "registers named supervision" do
|
26
|
+
called = []
|
27
|
+
supervision = Supervision.supervise_as(:danger) { called << 'method_call'}
|
28
|
+
supervision.call
|
29
|
+
expect(called).to eql(['method_call'])
|
30
|
+
expect(Supervision.circuit_system[:danger]).to eql(supervision)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when included as module" do
|
35
|
+
class RemoteApi
|
36
|
+
include Supervision
|
37
|
+
|
38
|
+
def danger_call(state)
|
39
|
+
state == :safe ? "hello" : raise(StandardError)
|
40
|
+
end
|
41
|
+
supervise_as(:danger, max_failures: 2) { |args| danger_call(args) }
|
42
|
+
|
43
|
+
def wrapped_danger
|
44
|
+
supervise { |args| danger_call(args) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows to call registerd circuit" do
|
49
|
+
api = RemoteApi.new
|
50
|
+
api.danger
|
51
|
+
api.danger
|
52
|
+
expect { api.danger }.to raise_error(Supervision::CircuitBreakerOpenError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end # Supervision
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Supervision::Registry do
|
4
|
+
|
5
|
+
let(:circuit) { Supervision.supervise { } }
|
6
|
+
|
7
|
+
subject(:registry) { described_class.new }
|
8
|
+
|
9
|
+
it "registers" do
|
10
|
+
registry[:danger] = circuit
|
11
|
+
expect(registry[:danger]).to eql(circuit)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "refuses to add non circuit object" do
|
15
|
+
expect {
|
16
|
+
registry[:danger] = Object.new
|
17
|
+
}.to raise_error(Supervision::TypeError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "" do
|
21
|
+
registry[:danger] = circuit
|
22
|
+
expect(registry.names).to eql([:danger])
|
23
|
+
end
|
24
|
+
|
25
|
+
it "" do
|
26
|
+
registry[:danger] = circuit
|
27
|
+
registry.delete(:danger)
|
28
|
+
expect(registry.names).to be_empty
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Supervision::TimeDSL do
|
6
|
+
it "defines millisecond/milliseconds/milli/millis" do
|
7
|
+
expect(1.millisecond).to eql(0.001)
|
8
|
+
expect(1.milli).to eql(0.001)
|
9
|
+
expect(10.milliseconds).to eql(0.01)
|
10
|
+
expect(10.millis).to eql(0.01)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "defines second/seconds" do
|
14
|
+
expect(1.second).to eql(1)
|
15
|
+
expect(10.seconds).to eql(10)
|
16
|
+
expect(1.sec).to eql(1)
|
17
|
+
expect(10.secs).to eql(10)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defines minute/minutes" do
|
21
|
+
expect(1.minute).to eql(60)
|
22
|
+
expect(10.minutes).to eql(600)
|
23
|
+
expect(1.min).to eql(60)
|
24
|
+
expect(10.mins).to eql(600)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "defines hours/hours" do
|
28
|
+
expect(1.hour).to eql(3600)
|
29
|
+
expect(2.hours).to eql(7200)
|
30
|
+
end
|
31
|
+
end
|
data/supervision.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'supervision/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "supervision"
|
8
|
+
spec.version = Supervision::VERSION
|
9
|
+
spec.authors = ["Piotr Murach"]
|
10
|
+
spec.email = [""]
|
11
|
+
spec.summary = %q{Write distributed systems that are resilient and self-heal.}
|
12
|
+
spec.description = %q{Write distributed systems that are resilient and self-heal. Remote calls can fail or hang indefinietly without a response. Supervision will help to isolate failure and keep individual components from bringing down the whole system.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "finite_machine", "~> 0.4"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
end
|
data/tasks/console.rake
ADDED
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'Run all specs'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc 'Run unit specs'
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run integration specs'
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rescue LoadError
|
24
|
+
%w[spec spec:unit spec:integration].each do |name|
|
25
|
+
task name do
|
26
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|