expeditor 0.5.0 → 0.6.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 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