expeditor 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -3
- data/CHANGELOG.md +5 -2
- data/README.md +14 -5
- data/examples/circuit_breaker.rb +27 -0
- data/lib/expeditor/bucket.rb +14 -8
- data/lib/expeditor/command.rb +5 -1
- data/lib/expeditor/service.rb +8 -2
- data/lib/expeditor/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06fd643997ffcbbcf94b5243a56f00a31e4788a3
|
4
|
+
data.tar.gz: 6aa12d927eab977c0d0b6c822b78b37877555637
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f81815f7920543475b352185f62dca303173988600a16db97b329662f72d6405e14b7efd834b3ff2eb7d393e9eccf3daa4a8eb4072d36997c33cdca2e1f16ea0
|
7
|
+
data.tar.gz: 1623ce5ccf9f6537e6ce87f0b056742dec4d71157c9108aedefbf4fd2924fa41211c50c76d13f8e9bedaa15d25a1192af2fe5d1f2994d2ad4f33cad7719788f6
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
## 0.6.0
|
2
|
+
- Improve default configuration of circuit breaker [#25](https://github.com/cookpad/expeditor/pull/25)
|
3
|
+
- Default `non_break_count` is reduced from 100 to 20
|
4
|
+
- Return proper status of service [#26](https://github.com/cookpad/expeditor/pull/26)
|
5
|
+
- Use `Expeditor::Service#status` instead of `#current_status`
|
2
6
|
|
3
7
|
## 0.5.0
|
4
|
-
|
5
8
|
- Add a `current_thread` option of `Expeditor::Command#start` method to execute a task on current thread [#13](https://github.com/cookpad/expeditor/pull/13)
|
6
9
|
- Drop support for MRI 2.0.x [#15](https://github.com/cookpad/expeditor/pull/15)
|
7
10
|
- Deprecate Expeditor::Command#with_fallback. Use `set_fallback` instead [#14](https://github.com/cookpad/expeditor/pull/14)
|
data/README.md
CHANGED
@@ -126,20 +126,29 @@ command = Expeditor::Command.new(service: service) do
|
|
126
126
|
...
|
127
127
|
end
|
128
128
|
|
129
|
-
service.
|
129
|
+
service.status
|
130
130
|
# => #<Expeditor::Status:0x007fdeeeb18468 @break=0, @dependency=0, @failure=0, @rejection=0, @success=0, @timeout=0>
|
131
131
|
|
132
132
|
service.reset_status! # reset status in the service
|
133
133
|
```
|
134
134
|
|
135
135
|
### circuit breaker
|
136
|
+
The circuit breaker needs a service metrics (success, failure, timeout, ...) to decide open the circuit or not.
|
137
|
+
Expeditor's circuit breaker has a few configuration for how it collects service metrics and how it opens the circuit.
|
138
|
+
|
139
|
+
For service metrics, Expeditor collects them with the given time window.
|
140
|
+
The metrics is guradually collected by breaking given time window into some peice of short time windows and resetting previous metrics when passing each short time window.
|
141
|
+
|
142
|
+
`non_break_count` is used to ignore requests to the service which is not frequentlly requested. Configure this value considering your estimated "requests per period to the service".
|
143
|
+
For example, when `period = 10` and `non_break_count = 20` and the requests do not occur more than 20 per 10 seconds, the circuit never opens because Expeditor ignores that "small number of requests".
|
144
|
+
If you don't ignore the failures in that case, set `non_break_count` to smaller value than `20`.
|
136
145
|
|
137
146
|
```ruby
|
138
147
|
service = Expeditor::Service.new(
|
139
|
-
|
140
|
-
sleep: 1,
|
141
|
-
|
142
|
-
|
148
|
+
threshold: 0.5, # If the failure rate is more than or equal to threshold, the circuit will be opened.
|
149
|
+
sleep: 1, # If once the circuit is opened, the circuit is still open until sleep time seconds is passed even though failure rate is less than threshold.
|
150
|
+
non_break_count: 20 # If the total count of metrics is not more than non_break_count, the circuit is not opened even though failure rate is more than threshold.
|
151
|
+
period: 10, # Time window of collecting metrics (in seconds).
|
143
152
|
)
|
144
153
|
|
145
154
|
command = Expeditor::Command.new(service: service) do
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'expeditor'
|
2
|
+
|
3
|
+
service = Expeditor::Service.new
|
4
|
+
|
5
|
+
i = 1
|
6
|
+
loop do
|
7
|
+
puts '=' * 100
|
8
|
+
p i
|
9
|
+
|
10
|
+
command = Expeditor::Command.new(service: service, timeout: 1) {
|
11
|
+
sleep 0.001 # simulate remote resource access
|
12
|
+
if File.exist?('foo')
|
13
|
+
'result'
|
14
|
+
else
|
15
|
+
raise 'Demo error'
|
16
|
+
end
|
17
|
+
}.set_fallback { |e|
|
18
|
+
p e
|
19
|
+
'default value'
|
20
|
+
}.start
|
21
|
+
|
22
|
+
p command.get
|
23
|
+
p service.status
|
24
|
+
puts
|
25
|
+
|
26
|
+
i += 1
|
27
|
+
end
|
data/lib/expeditor/bucket.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'expeditor/status'
|
2
2
|
|
3
3
|
module Expeditor
|
4
|
+
# Bucket is a data structure like circular buffer. It holds some status
|
5
|
+
# objects and it rolls statuses each `per` time (default is 1 second). Once
|
6
|
+
# it reaches the end of statuses array, it backs to start of statuses array
|
7
|
+
# and then reset the status and resumes recording. This is done so that the
|
8
|
+
# statistics are recorded gradually with short time interval rahter than
|
9
|
+
# reset all the record every wide time range (default is 10 seconds).
|
4
10
|
class Bucket
|
5
11
|
def initialize(opts = {})
|
6
12
|
@mutex = Mutex.new
|
@@ -23,14 +29,14 @@ module Expeditor
|
|
23
29
|
def total
|
24
30
|
acc = @mutex.synchronize do
|
25
31
|
update
|
26
|
-
@statuses.inject([0, 0, 0, 0, 0, 0]) do |
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
@statuses.inject([0, 0, 0, 0, 0, 0]) do |i, s|
|
33
|
+
i[0] += s.success
|
34
|
+
i[1] += s.failure
|
35
|
+
i[2] += s.rejection
|
36
|
+
i[3] += s.timeout
|
37
|
+
i[4] += s.break
|
38
|
+
i[5] += s.dependency
|
39
|
+
i
|
34
40
|
end
|
35
41
|
end
|
36
42
|
status = Expeditor::Status.new
|
data/lib/expeditor/command.rb
CHANGED
@@ -238,7 +238,11 @@ module Expeditor
|
|
238
238
|
if @fallback_block
|
239
239
|
future = RichFuture.new(executor: executor) do
|
240
240
|
success, value, reason = Concurrent::SafeTaskExecutor.new(@fallback_block, rescue_exception: true).execute(reason)
|
241
|
-
|
241
|
+
if success
|
242
|
+
@ivar.set(value)
|
243
|
+
else
|
244
|
+
@ivar.fail(reason)
|
245
|
+
end
|
242
246
|
end
|
243
247
|
future.safe_execute
|
244
248
|
else
|
data/lib/expeditor/service.rb
CHANGED
@@ -7,8 +7,8 @@ module Expeditor
|
|
7
7
|
|
8
8
|
def initialize(opts = {})
|
9
9
|
@executor = opts.fetch(:executor) { Concurrent::ThreadPoolExecutor.new }
|
10
|
-
@threshold = opts.fetch(:threshold, 0.5)
|
11
|
-
@non_break_count = opts.fetch(:non_break_count,
|
10
|
+
@threshold = opts.fetch(:threshold, 0.5)
|
11
|
+
@non_break_count = opts.fetch(:non_break_count, 20)
|
12
12
|
@sleep = opts.fetch(:sleep, 1)
|
13
13
|
@bucket_opts = {
|
14
14
|
size: 10,
|
@@ -70,7 +70,13 @@ module Expeditor
|
|
70
70
|
@executor.shutdown
|
71
71
|
end
|
72
72
|
|
73
|
+
def status
|
74
|
+
@bucket.total
|
75
|
+
end
|
76
|
+
|
77
|
+
# @deprecated
|
73
78
|
def current_status
|
79
|
+
warn 'Expeditor::Service#current_status is deprecated. Please use #status instead'
|
74
80
|
@bucket.current
|
75
81
|
end
|
76
82
|
|
data/lib/expeditor/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: expeditor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- shohei-yasutake
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- Rakefile
|
112
112
|
- bin/console
|
113
113
|
- bin/setup
|
114
|
+
- examples/circuit_breaker.rb
|
114
115
|
- examples/example.rb
|
115
116
|
- expeditor.gemspec
|
116
117
|
- lib/expeditor.rb
|
@@ -143,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
144
|
version: '0'
|
144
145
|
requirements: []
|
145
146
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.6.11
|
147
148
|
signing_key:
|
148
149
|
specification_version: 4
|
149
150
|
summary: Expeditor provides asynchronous execution and fault tolerance for microservices
|