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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ee9877b9a720af63ec3a4163d680e43d734c4b7
4
- data.tar.gz: 8707da47bb651151d0c9a2306dcbe237e165cfe5
3
+ metadata.gz: 06fd643997ffcbbcf94b5243a56f00a31e4788a3
4
+ data.tar.gz: 6aa12d927eab977c0d0b6c822b78b37877555637
5
5
  SHA512:
6
- metadata.gz: 7889e85b9081df0c1aecc1039e0b2193224effe67d5169c6c100027714909b4616cb5c913a02d808bdf0e21669cdfd36ea22829dea1eb4bdc09df8dc0a8e95b5
7
- data.tar.gz: c36f0c9b174b2043de7da8628afa6379f655d38a57538d99669e5124e24eff5e067ed96ad209e0a25ddc70cdcdaf7171c3de21c9ffbcb99e85ef78c6015b3864
6
+ metadata.gz: f81815f7920543475b352185f62dca303173988600a16db97b329662f72d6405e14b7efd834b3ff2eb7d393e9eccf3daa4a8eb4072d36997c33cdca2e1f16ea0
7
+ data.tar.gz: 1623ce5ccf9f6537e6ce87f0b056742dec4d71157c9108aedefbf4fd2924fa41211c50c76d13f8e9bedaa15d25a1192af2fe5d1f2994d2ad4f33cad7719788f6
@@ -2,9 +2,10 @@ language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.1
6
- - 2.2
7
- - 2.3.0
5
+ - 2.1.10
6
+ - 2.2.6
7
+ - 2.3.3
8
+ - 2.4.0
8
9
  - ruby-head
9
10
  matrix:
10
11
  allow_failures:
@@ -1,7 +1,10 @@
1
- <!-- ## Master (unreleased) -->
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.current_status
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
- period: 10, # retention period of the service metrics (success, failure, timeout, ...)
140
- sleep: 1, # if once the circuit is opened, the circuit is still open until sleep time is passed even though failure rate is less than threshold
141
- threshold: 0.5, # if the failure rate is more than or equal to threshold, the circuit is opened
142
- non_break_count: 100 # 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
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
@@ -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 |acc, s|
27
- acc[0] += s.success
28
- acc[1] += s.failure
29
- acc[2] += s.rejection
30
- acc[3] += s.timeout
31
- acc[4] += s.break
32
- acc[5] += s.dependency
33
- acc
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
@@ -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
- @ivar.send(:complete, success, value, reason)
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
@@ -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) # is 0.5 ok?
11
- @non_break_count = opts.fetch(:non_break_count, 100) # is 100 ok?
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
 
@@ -1,3 +1,3 @@
1
1
  module Expeditor
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
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.5.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: 2016-08-29 00:00:00.000000000 Z
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.5.1
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