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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2380a72a4938ad53fc206f4e155805d90568477f
4
- data.tar.gz: e5ee71ae7e689318b764c47e969e16983330846a
3
+ metadata.gz: 5ee9877b9a720af63ec3a4163d680e43d734c4b7
4
+ data.tar.gz: 8707da47bb651151d0c9a2306dcbe237e165cfe5
5
5
  SHA512:
6
- metadata.gz: 157aeae73bb32ab82848b7a97f8fa38a7c3a3f56419e59c3b2d71002c5194d5fcd2b7dce86ad7be4cad1406f2844dacf2c8f630ecf3f5e0245b018c6717beb7f
7
- data.tar.gz: 575962fba75f61364cf1f998c01c7636d100a10e0e345d68488871c6a9735ee371251e332f33221c3780987719cd8fdf725454bac56d268f1405c562934864dd
6
+ metadata.gz: 7889e85b9081df0c1aecc1039e0b2193224effe67d5169c6c100027714909b4616cb5c913a02d808bdf0e21669cdfd36ea22829dea1eb4bdc09df8dc0a8e95b5
7
+ data.tar.gz: c36f0c9b174b2043de7da8628afa6379f655d38a57538d99669e5124e24eff5e067ed96ad209e0a25ddc70cdcdaf7171c3de21c9ffbcb99e85ef78c6015b3864
@@ -2,7 +2,6 @@ language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.0.0
6
5
  - 2.1
7
6
  - 2.2
8
7
  - 2.3.0
@@ -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.with_fallback do |e|
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.
@@ -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.with_fallback do |e|
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.with_fallback do
47
+ command4_d = command4.set_fallback do
48
48
  'command4 fallback'
49
49
  end
50
50
 
@@ -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"
@@ -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
- @normal_future = initial_normal(&block)
18
- @fallback_var = nil
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
- def start
23
- if not started?
24
- @dependencies.each(&:start)
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(retryable_options = {})
32
- if not started?
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 if not started?
52
+ raise NotStartedError unless started?
45
53
  @normal_future.get_or_else do
46
- if @fallback_var && @service.fallback_enabled?
47
- @fallback_var.wait
48
- if @fallback_var.rejected?
49
- raise @fallback_var.reason
54
+ if @fallback_block && @service.fallback_enabled?
55
+ @ivar.wait
56
+ if @ivar.rejected?
57
+ raise @ivar.reason
50
58
  else
51
- @fallback_var.value
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
- command = self.clone
61
- command.reset_fallback(&block)
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 if not started?
67
- @normal_future.wait
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
- protected
126
+ private
113
127
 
114
128
  def reset_fallback(&block)
115
- @fallback_var = Concurrent::IVar.new
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: @service.executor) do
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
- if @fallback_var
228
- @fallback_var.add_observer(&callback)
229
- else
230
- @normal_future.add_observer(&callback)
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
- @service = Expeditor::Services.default
237
- @dependencies = []
238
- @normal_future = RichFuture.new {}.set(value)
257
+ super(){ value }
258
+ self.start
239
259
  end
240
260
  end
241
261
  end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Expeditor
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.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.4.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-07-25 00:00:00.000000000 Z
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: '0'
138
+ version: 2.1.0
139
139
  required_rubygems_version: !ruby/object:Gem::Requirement
140
140
  requirements:
141
141
  - - ">="