rcb 0.1.0 → 0.2.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 +4 -4
- data/.github/workflows/action.yaml +22 -0
- data/README.md +4 -1
- data/lib/rcb.rb +2 -2
- data/lib/rcb/configuration.rb +57 -27
- data/lib/rcb/instance.rb +0 -1
- data/lib/rcb/state.rb +8 -6
- data/rcb.gemspec +1 -3
- metadata +3 -3
- data/lib/rcb/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '029e8ceda425ad3aea544142ab9307fd74ebff19fa98e359d791d820528f5638'
|
4
|
+
data.tar.gz: daf71c637318058ef6647531544c4fbe77404e08e0e705778ea77623f53d461d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79cf1a6056c40f5abf501905ea0a3ac12e98eaaafd86a45e537b4db66ce343b6bc7c759c5ba74a7c7a0f1c7d66ec4e4c4f881c8e02f6627cbb89acab426fba29
|
7
|
+
data.tar.gz: b268096b37b3a3d13f7a7367ad5491b02dd65bbf21aa47637caa7f7afb67586470917b984913cf016e23d0d0c8020cddc0a4dbce16067189a2a79b95b4bc8df3
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: test
|
2
|
+
on: [push, pull_request]
|
3
|
+
|
4
|
+
jobs:
|
5
|
+
build:
|
6
|
+
runs-on: ubuntu-latest
|
7
|
+
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v1
|
10
|
+
|
11
|
+
- name: Set up Ruby 2.7
|
12
|
+
uses: clupprich/ruby-build-action@master
|
13
|
+
with:
|
14
|
+
ruby-version: 2.7.0
|
15
|
+
|
16
|
+
- name: Bundle install
|
17
|
+
run: |
|
18
|
+
bundle -j 4 --path vendor/bundle
|
19
|
+
|
20
|
+
- name: Run Tests
|
21
|
+
run: |
|
22
|
+
bundle exec rake test
|
data/README.md
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# Rcb - Ruby Circuit Breaker
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/rcb)
|
4
|
+
[](https://github.com/petitviolet/rcb/actions)
|
5
|
+
|
3
6
|
[Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html) implementation for/by Ruby.
|
4
7
|
CircuitBreaker is a great pattern to build robust system consists of bunch of microservices.
|
5
8
|
|
6
9
|
- Close
|
7
|
-
-
|
10
|
+
- An operational state
|
8
11
|
- Open
|
9
12
|
- A not operational state
|
10
13
|
- Half Open
|
data/lib/rcb.rb
CHANGED
@@ -3,9 +3,9 @@ require_relative "./rcb/configuration"
|
|
3
3
|
|
4
4
|
module Rcb
|
5
5
|
module ClassMethods
|
6
|
-
def for(tag,
|
6
|
+
def for(tag, open_condition: nil, reset_timeout_msec: nil)
|
7
7
|
config = Rcb::Configurations.for(tag,
|
8
|
-
|
8
|
+
open_condition: open_condition,
|
9
9
|
reset_timeout_msec: reset_timeout_msec)
|
10
10
|
Instance.new(config)
|
11
11
|
end
|
data/lib/rcb/configuration.rb
CHANGED
@@ -1,53 +1,83 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'rstructural'
|
2
3
|
|
3
4
|
module Rcb
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
OpenCondition = Rstruct.new(:max_failure_count, :window_msec) do
|
6
|
+
self::DEFAULT = new(3, 1000).freeze
|
7
|
+
end
|
8
|
+
|
9
|
+
Config = Rstruct.new(:tag, :open_condition, :reset_timeout_msec) do
|
10
|
+
self::RESET_TIMEOUT_MSEC = 1000.freeze
|
7
11
|
|
8
12
|
@logger = Logger.new($stderr)
|
9
13
|
|
10
|
-
def self.create(tag,
|
14
|
+
def self.create(tag, open_condition: nil, reset_timeout_msec: nil)
|
11
15
|
raise 'Rcb tag must not be nil' if tag.nil?
|
12
16
|
|
13
|
-
if
|
17
|
+
if open_condition.nil? && reset_timeout_msec.nil?
|
14
18
|
@logger.warn("Rcb for '#{tag}' is not configured!")
|
15
19
|
end
|
16
20
|
|
17
21
|
Config.new(
|
18
22
|
tag.to_s.to_sym,
|
19
|
-
|
20
|
-
reset_timeout_msec || RESET_TIMEOUT_MSEC
|
23
|
+
open_condition || OpenCondition::DEFAULT,
|
24
|
+
reset_timeout_msec || Config::RESET_TIMEOUT_MSEC
|
21
25
|
)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
module DSL
|
30
|
+
class OpenConditionBuilder
|
31
|
+
def initialize
|
32
|
+
@max_failure_count = nil
|
33
|
+
@window_msec = nil
|
34
|
+
end
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
def max_failure_count(count)
|
37
|
+
@max_failure_count = count
|
38
|
+
end
|
39
|
+
|
40
|
+
def window_msec(msec)
|
41
|
+
@window_msec = msec
|
42
|
+
end
|
35
43
|
|
36
|
-
|
37
|
-
|
44
|
+
def build
|
45
|
+
Rcb::OpenCondition.new(@max_failure_count, @window_msec)
|
46
|
+
end
|
38
47
|
end
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
@tag
|
43
|
-
|
44
|
-
reset_timeout_msec
|
45
|
-
|
49
|
+
class ConfigBuilder
|
50
|
+
def initialize(tag)
|
51
|
+
@tag = tag
|
52
|
+
@open_condition_builder = OpenConditionBuilder.new
|
53
|
+
@reset_timeout_msec = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def open_condition(hash = nil)
|
57
|
+
if hash
|
58
|
+
@open_condition_builder.max_failure_count hash[:max_failure_count]
|
59
|
+
@open_condition_builder.window_msec hash[:window_msec]
|
60
|
+
else
|
61
|
+
@open_condition_builder
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def reset_timeout_msec(msec)
|
66
|
+
@reset_timeout_msec = msec
|
67
|
+
end
|
68
|
+
|
69
|
+
def build
|
70
|
+
Rcb::Config.create(
|
71
|
+
@tag,
|
72
|
+
open_condition: @open_condition_builder.build,
|
73
|
+
reset_timeout_msec: @reset_timeout_msec
|
74
|
+
).freeze
|
75
|
+
end
|
46
76
|
end
|
47
77
|
end
|
48
78
|
|
49
79
|
def Rcb.configure(tag, &block)
|
50
|
-
c = ConfigBuilder.new(tag.to_s.to_sym)
|
80
|
+
c = DSL::ConfigBuilder.new(tag.to_s.to_sym)
|
51
81
|
.tap { |cb| block.call(cb) }
|
52
82
|
.build
|
53
83
|
|
@@ -57,9 +87,9 @@ module Rcb
|
|
57
87
|
module Configurations
|
58
88
|
@configs = {}
|
59
89
|
|
60
|
-
def self.for(tag,
|
90
|
+
def self.for(tag, open_condition: nil, reset_timeout_msec: nil)
|
61
91
|
@configs[tag.to_s.to_sym] || Config.create(tag,
|
62
|
-
|
92
|
+
open_condition: open_condition,
|
63
93
|
reset_timeout_msec: reset_timeout_msec)
|
64
94
|
end
|
65
95
|
|
data/lib/rcb/instance.rb
CHANGED
data/lib/rcb/state.rb
CHANGED
@@ -5,18 +5,20 @@ require_relative './error'
|
|
5
5
|
module Rcb::State
|
6
6
|
extend ADT
|
7
7
|
|
8
|
-
Close = data :
|
9
|
-
def self.create
|
10
|
-
new(
|
8
|
+
Close = data :failure_times do
|
9
|
+
def self.create
|
10
|
+
new([])
|
11
11
|
end
|
12
12
|
|
13
|
-
def run(config, &block)
|
13
|
+
def run(config, now: Time.now.utc, &block)
|
14
14
|
case try_call(&block)
|
15
15
|
in Either::Right[result]
|
16
16
|
Rcb::Result::Ok.new(self, result)
|
17
17
|
in Either::Left[e]
|
18
|
-
|
19
|
-
|
18
|
+
old_limit = now - (config.open_condition.window_msec / 1000.0)
|
19
|
+
refreshed_failure_times = failure_times.filter { |ft| old_limit <= ft } + [now]
|
20
|
+
if refreshed_failure_times.size < config.open_condition.max_failure_count
|
21
|
+
Rcb::Result::Ng.new(Close.new(refreshed_failure_times), e)
|
20
22
|
else
|
21
23
|
Rcb::Result::Ng.new(Open.create, e)
|
22
24
|
end
|
data/rcb.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rcb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- petitviolet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rstructural
|
@@ -73,6 +73,7 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- ".github/workflows/action.yaml"
|
76
77
|
- ".gitignore"
|
77
78
|
- CODE_OF_CONDUCT.md
|
78
79
|
- Gemfile
|
@@ -87,7 +88,6 @@ files:
|
|
87
88
|
- lib/rcb/instance.rb
|
88
89
|
- lib/rcb/result.rb
|
89
90
|
- lib/rcb/state.rb
|
90
|
-
- lib/rcb/version.rb
|
91
91
|
- rcb.gemspec
|
92
92
|
homepage: https://github.com/petitviolet/rcb
|
93
93
|
licenses:
|
data/lib/rcb/version.rb
DELETED