expeditor 0.4.0 → 0.5.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/.travis.yml +0 -1
- data/CHANGELOG.md +9 -0
- data/README.md +23 -1
- data/examples/example.rb +2 -2
- data/expeditor.gemspec +2 -0
- data/lib/expeditor/command.rb +65 -45
- data/lib/expeditor/errors.rb +5 -0
- data/lib/expeditor/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ee9877b9a720af63ec3a4163d680e43d734c4b7
|
4
|
+
data.tar.gz: 8707da47bb651151d0c9a2306dcbe237e165cfe5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7889e85b9081df0c1aecc1039e0b2193224effe67d5169c6c100027714909b4616cb5c913a02d808bdf0e21669cdfd36ea22829dea1eb4bdc09df8dc0a8e95b5
|
7
|
+
data.tar.gz: c36f0c9b174b2043de7da8628afa6379f655d38a57538d99669e5124e24eff5e067ed96ad209e0a25ddc70cdcdaf7171c3de21c9ffbcb99e85ef78c6015b3864
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
<!-- ## Master (unreleased) -->
|
2
|
+
|
3
|
+
## 0.5.0
|
4
|
+
|
5
|
+
- 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
|
+
- Drop support for MRI 2.0.x [#15](https://github.com/cookpad/expeditor/pull/15)
|
7
|
+
- Deprecate Expeditor::Command#with_fallback. Use `set_fallback` instead [#14](https://github.com/cookpad/expeditor/pull/14)
|
8
|
+
- Do not allow set_fallback call after command is started. [#18](https://github.com/cookpad/expeditor/pull/18)
|
9
|
+
|
1
10
|
## 0.4.0
|
2
11
|
- Add Expeditor::Service#current\_status [#9](https://github.com/cookpad/expeditor/issues/9)
|
3
12
|
- Add Expeditor::Service#reset\_status! [#10](https://github.com/cookpad/expeditor/issues/10)
|
data/README.md
CHANGED
@@ -8,6 +8,8 @@ It is inspired by [Netflix/Hystrix](https://github.com/Netflix/Hystrix).
|
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
+
Expeditor currently supports Ruby 2.1 and higher.
|
12
|
+
|
11
13
|
Add this line to your application's Gemfile:
|
12
14
|
|
13
15
|
```ruby
|
@@ -68,7 +70,7 @@ command = Expeditor::Command.new do
|
|
68
70
|
end
|
69
71
|
|
70
72
|
# use fallback value if command is failed
|
71
|
-
command_with_fallback = command.
|
73
|
+
command_with_fallback = command.set_fallback do |e|
|
72
74
|
log(e)
|
73
75
|
default_value
|
74
76
|
end
|
@@ -145,6 +147,26 @@ command = Expeditor::Command.new(service: service) do
|
|
145
147
|
end
|
146
148
|
```
|
147
149
|
|
150
|
+
### synchronous execution
|
151
|
+
|
152
|
+
Use `current_thread` option of `#start`, command executes synchronous on current thread.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
command1 = Expeditor::Command.new do
|
156
|
+
...
|
157
|
+
end
|
158
|
+
|
159
|
+
command2 = Expeditor::Command.new do
|
160
|
+
...
|
161
|
+
end
|
162
|
+
|
163
|
+
command1.start(current_thread: true) # blocking
|
164
|
+
command2.start(current_thread: true) # blocking
|
165
|
+
|
166
|
+
command1.get
|
167
|
+
command2.get
|
168
|
+
```
|
169
|
+
|
148
170
|
## Development
|
149
171
|
|
150
172
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/examples/example.rb
CHANGED
@@ -24,7 +24,7 @@ command2 = Expeditor::Command.new(service: service, timeout: 0.5) do
|
|
24
24
|
'command2'
|
25
25
|
end
|
26
26
|
# command2_d is command2 with fallback
|
27
|
-
command2_d = command2.
|
27
|
+
command2_d = command2.set_fallback do |e|
|
28
28
|
'command2 fallback'
|
29
29
|
end
|
30
30
|
|
@@ -44,7 +44,7 @@ command4 = Expeditor::Command.new(
|
|
44
44
|
sleep 0.3
|
45
45
|
v2 + ', ' + v3
|
46
46
|
end
|
47
|
-
command4_d = command4.
|
47
|
+
command4_d = command4.set_fallback do
|
48
48
|
'command4 fallback'
|
49
49
|
end
|
50
50
|
|
data/expeditor.gemspec
CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
+
spec.required_ruby_version = '>= 2.1.0'
|
23
|
+
|
22
24
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0.0"
|
23
25
|
spec.add_runtime_dependency "concurrent-ruby-ext", "~> 1.0.0"
|
24
26
|
spec.add_runtime_dependency "retryable", "> 1.0"
|
data/lib/expeditor/command.rb
CHANGED
@@ -14,41 +14,49 @@ module Expeditor
|
|
14
14
|
@service = opts.fetch(:service, Expeditor::Services.default)
|
15
15
|
@timeout = opts[:timeout]
|
16
16
|
@dependencies = opts.fetch(:dependencies, [])
|
17
|
-
|
18
|
-
@
|
17
|
+
|
18
|
+
@normal_future = nil
|
19
19
|
@retryable_options = Concurrent::IVar.new
|
20
|
+
@normal_block = block
|
21
|
+
@fallback_block = nil
|
22
|
+
@ivar = Concurrent::IVar.new
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
# @param current_thread [Boolean] Execute the task on current thread(blocking)
|
26
|
+
def start(current_thread: false)
|
27
|
+
unless started?
|
28
|
+
if current_thread
|
29
|
+
prepare(Concurrent::ImmediateExecutor.new)
|
30
|
+
else
|
31
|
+
prepare
|
32
|
+
end
|
25
33
|
@normal_future.safe_execute
|
26
34
|
end
|
27
35
|
self
|
28
36
|
end
|
29
37
|
|
30
38
|
# Equivalent to retryable gem options
|
31
|
-
def start_with_retry(
|
32
|
-
|
39
|
+
def start_with_retry(current_thread: false, **retryable_options)
|
40
|
+
unless started?
|
33
41
|
@retryable_options.set(retryable_options)
|
34
|
-
start
|
42
|
+
start(current_thread: current_thread)
|
35
43
|
end
|
36
44
|
self
|
37
45
|
end
|
38
46
|
|
39
47
|
def started?
|
40
|
-
@normal_future.executed?
|
48
|
+
@normal_future && @normal_future.executed?
|
41
49
|
end
|
42
50
|
|
43
51
|
def get
|
44
|
-
raise NotStartedError
|
52
|
+
raise NotStartedError unless started?
|
45
53
|
@normal_future.get_or_else do
|
46
|
-
if @
|
47
|
-
@
|
48
|
-
if @
|
49
|
-
raise @
|
54
|
+
if @fallback_block && @service.fallback_enabled?
|
55
|
+
@ivar.wait
|
56
|
+
if @ivar.rejected?
|
57
|
+
raise @ivar.reason
|
50
58
|
else
|
51
|
-
@
|
59
|
+
@ivar.value
|
52
60
|
end
|
53
61
|
else
|
54
62
|
raise @normal_future.reason
|
@@ -56,16 +64,22 @@ module Expeditor
|
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
67
|
+
def set_fallback(&block)
|
68
|
+
if started?
|
69
|
+
raise AlreadyStartedError, "Do not allow set_fallback call after command is started"
|
70
|
+
end
|
71
|
+
reset_fallback(&block)
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
59
75
|
def with_fallback(&block)
|
60
|
-
|
61
|
-
|
62
|
-
command
|
76
|
+
warn 'Expeditor::Command#with_fallback is deprecated. Please use set_fallback instead'
|
77
|
+
set_fallback(&block)
|
63
78
|
end
|
64
79
|
|
65
80
|
def wait
|
66
|
-
raise NotStartedError
|
67
|
-
@
|
68
|
-
@fallback_var.wait if @fallback_var && @service.fallback_enabled?
|
81
|
+
raise NotStartedError unless started?
|
82
|
+
@ivar.wait
|
69
83
|
end
|
70
84
|
|
71
85
|
# command.on_complete do |success, value, reason|
|
@@ -109,25 +123,12 @@ module Expeditor
|
|
109
123
|
Command.new(opts, &block).start
|
110
124
|
end
|
111
125
|
|
112
|
-
|
126
|
+
private
|
113
127
|
|
114
128
|
def reset_fallback(&block)
|
115
|
-
@
|
116
|
-
@normal_future.add_observer do |_, value, reason|
|
117
|
-
if reason != nil
|
118
|
-
future = RichFuture.new(executor: Concurrent.global_io_executor) do
|
119
|
-
success, val, reason = Concurrent::SafeTaskExecutor.new(block, rescue_exception: true).execute(reason)
|
120
|
-
@fallback_var.send(:complete, success, val, reason)
|
121
|
-
end
|
122
|
-
future.safe_execute
|
123
|
-
else
|
124
|
-
@fallback_var.send(:complete, true, value, nil)
|
125
|
-
end
|
126
|
-
end
|
129
|
+
@fallback_block = block
|
127
130
|
end
|
128
131
|
|
129
|
-
private
|
130
|
-
|
131
132
|
def breakable_block(args, &block)
|
132
133
|
if @service.open?
|
133
134
|
raise CircuitBreakError
|
@@ -181,8 +182,8 @@ module Expeditor
|
|
181
182
|
# end
|
182
183
|
# end
|
183
184
|
# end
|
184
|
-
def initial_normal(&block)
|
185
|
-
future = RichFuture.new(executor:
|
185
|
+
def initial_normal(executor, &block)
|
186
|
+
future = RichFuture.new(executor: executor) do
|
186
187
|
args = wait_dependencies
|
187
188
|
timeout_block(args, &block)
|
188
189
|
end
|
@@ -224,18 +225,37 @@ module Expeditor
|
|
224
225
|
end
|
225
226
|
|
226
227
|
def on(&callback)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
228
|
+
@ivar.add_observer(&callback)
|
229
|
+
end
|
230
|
+
|
231
|
+
# set future
|
232
|
+
# set fallback future as an observer
|
233
|
+
# start dependencies
|
234
|
+
def prepare(executor = @service.executor)
|
235
|
+
@normal_future = initial_normal(executor, &@normal_block)
|
236
|
+
@normal_future.add_observer do |_, value, reason|
|
237
|
+
if reason # failure
|
238
|
+
if @fallback_block
|
239
|
+
future = RichFuture.new(executor: executor) do
|
240
|
+
success, value, reason = Concurrent::SafeTaskExecutor.new(@fallback_block, rescue_exception: true).execute(reason)
|
241
|
+
@ivar.send(:complete, success, value, reason)
|
242
|
+
end
|
243
|
+
future.safe_execute
|
244
|
+
else
|
245
|
+
@ivar.fail(reason)
|
246
|
+
end
|
247
|
+
else # success
|
248
|
+
@ivar.set(value)
|
249
|
+
end
|
231
250
|
end
|
251
|
+
|
252
|
+
@dependencies.each(&:start)
|
232
253
|
end
|
233
254
|
|
234
255
|
class ConstCommand < Command
|
235
256
|
def initialize(value)
|
236
|
-
|
237
|
-
|
238
|
-
@normal_future = RichFuture.new {}.set(value)
|
257
|
+
super(){ value }
|
258
|
+
self.start
|
239
259
|
end
|
240
260
|
end
|
241
261
|
end
|
data/lib/expeditor/errors.rb
CHANGED
@@ -4,10 +4,15 @@ module Expeditor
|
|
4
4
|
NotStartedError = Class.new(StandardError)
|
5
5
|
RejectedExecutionError = Concurrent::RejectedExecutionError
|
6
6
|
CircuitBreakError = Class.new(StandardError)
|
7
|
+
AlreadyStartedError = Class.new(StandardError)
|
7
8
|
class DependencyError < StandardError
|
8
9
|
attr :error
|
9
10
|
def initialize(e)
|
10
11
|
@error = e
|
11
12
|
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
@error.message
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
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.5.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-
|
11
|
+
date: 2016-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -135,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 2.1.0
|
139
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
141
|
- - ">="
|