aws-flow 2.4.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +8 -8
  2. data/aws-flow.gemspec +1 -0
  3. data/lib/aws/decider.rb +0 -1
  4. data/lib/aws/decider/starter.rb +6 -8
  5. data/lib/aws/decider/utilities.rb +6 -0
  6. data/lib/aws/decider/version.rb +1 -1
  7. data/lib/aws/decider/worker.rb +6 -0
  8. data/lib/aws/flow/future.rb +86 -6
  9. data/lib/aws/flow/implementation.rb +84 -13
  10. data/lib/aws/runner.rb +1 -1
  11. data/lib/aws/templates.rb +2 -0
  12. data/lib/aws/templates/activity.rb +41 -0
  13. data/lib/aws/templates/default.rb +11 -8
  14. data/lib/aws/templates/result.rb +183 -0
  15. data/lib/aws/templates/starter.rb +152 -226
  16. data/lib/aws/templates/utilities.rb +59 -0
  17. data/spec/aws/decider/integration/activity_spec.rb +1 -0
  18. data/spec/aws/decider/integration/options_spec.rb +16 -9
  19. data/spec/aws/decider/integration/starter_spec.rb +6 -7
  20. data/spec/aws/decider/unit/starter_spec.rb +2 -2
  21. data/spec/aws/decider/unit/worker_spec.rb +42 -0
  22. data/spec/aws/flow/{async_backtrace_spec.rb → unit/async_backtrace_spec.rb} +0 -0
  23. data/spec/aws/flow/{async_scope_spec.rb → unit/async_scope_spec.rb} +0 -0
  24. data/spec/aws/flow/{begin_rescue_ensure_spec.rb → unit/begin_rescue_ensure_spec.rb} +0 -0
  25. data/spec/aws/flow/unit/external_condition_variable_spec.rb +59 -0
  26. data/spec/aws/flow/{external_task_spec.rb → unit/external_task_spec.rb} +0 -0
  27. data/spec/aws/flow/{factories.rb → unit/factories.rb} +0 -0
  28. data/spec/aws/flow/{fiber_condition_variable_spec.rb → unit/fiber_condition_variable_spec.rb} +0 -0
  29. data/spec/aws/flow/{fiber_spec.rb → unit/fiber_spec.rb} +0 -0
  30. data/spec/aws/flow/{flow_spec.rb → unit/flow_spec.rb} +0 -0
  31. data/spec/aws/flow/{future_spec.rb → unit/future_spec.rb} +188 -0
  32. data/spec/aws/flow/{simple_dfa_spec.rb → unit/simple_dfa_spec.rb} +0 -0
  33. data/spec/aws/runner/integration/runner_integration_spec.rb +1 -0
  34. data/spec/aws/runner/unit/runner_unit_spec.rb +3 -3
  35. data/spec/aws/templates/unit/activity_spec.rb +9 -10
  36. data/spec/aws/templates/unit/base_spec.rb +10 -11
  37. data/spec/aws/templates/unit/default_spec.rb +23 -6
  38. data/spec/aws/templates/unit/result_spec.rb +130 -0
  39. data/spec/aws/templates/unit/starter_spec.rb +32 -105
  40. data/spec/aws/templates/unit/utilities_spec.rb +80 -0
  41. metadata +19 -13
@@ -0,0 +1,59 @@
1
+ module AWS
2
+ module Flow
3
+ module Templates
4
+
5
+ module Utils
6
+
7
+ # This method calls the given block. If an UnknownResourceFault is
8
+ # returned, then it tries to register AWS Flow defaults with the service
9
+ # and calls the block again.
10
+ def self.register_on_failure(domain, &block)
11
+ begin
12
+ block.call(domain)
13
+ rescue AWS::SimpleWorkflow::Errors::UnknownResourceFault => e
14
+ register_defaults(domain)
15
+ block.call(domain)
16
+ end
17
+ end
18
+
19
+ # Registers the relevant defaults with the Simple Workflow Service. If
20
+ # domain name is not provided, it registers the FlowDefault domain
21
+ # @api private
22
+ def self.register_defaults(name=nil)
23
+ name ||= FlowConstants.defaults[:domain]
24
+ domain = AWS::Flow::Utilities.register_domain(name)
25
+
26
+ register_default_workflow(domain)
27
+ register_default_result_activity(domain)
28
+ end
29
+
30
+ # Registers the default workflow type FlowDefaultWorkflowRuby with the
31
+ # Simple Workflow Service
32
+ # @api private
33
+ def self.register_default_workflow(domain)
34
+ AWS::Flow::WorkflowWorker.new(
35
+ domain.client,
36
+ domain,
37
+ nil,
38
+ AWS::Flow::Templates.default_workflow
39
+ ).register
40
+ end
41
+
42
+ # Registers the default result activity type FlowDefaultResultActivityRuby
43
+ # with the Simple Workflow Service
44
+ # @api private
45
+ def self.register_default_result_activity(domain)
46
+ worker = AWS::Flow::ActivityWorker.new(
47
+ domain.client,
48
+ domain,
49
+ nil,
50
+ AWS::Flow::Templates.result_activity
51
+ ) {{ use_forking: false }}
52
+ worker.register
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -5,6 +5,7 @@ describe Activities do
5
5
  @bucket = ENV['AWS_SWF_BUCKET_NAME']
6
6
  ENV['AWS_SWF_BUCKET_NAME'] = nil
7
7
  @swf, @domain = setup_swf
8
+ kill_executors
8
9
  end
9
10
 
10
11
  after(:all) do
@@ -4,6 +4,7 @@ describe "task_priority" do
4
4
 
5
5
  before(:all) do
6
6
  @swf, @domain = setup_swf
7
+ kill_executors
7
8
  end
8
9
 
9
10
  context "activities and workflows" do
@@ -117,7 +118,8 @@ describe "task_priority" do
117
118
  {
118
119
  version: "1.0",
119
120
  default_task_priority: 50,
120
- default_execution_start_to_close_timeout: 60
121
+ default_execution_start_to_close_timeout: 60,
122
+ default_tag_list: ["continue_task_priority_test"]
121
123
  }
122
124
  end
123
125
  def entry_point
@@ -140,6 +142,7 @@ describe "task_priority" do
140
142
  execution.status.should == :continued_as_new
141
143
  events = execution.events.select { |x| x.event_type == "WorkflowExecutionContinuedAsNew" }
142
144
  events.first.attributes.task_priority.should == 50
145
+ @domain.workflow_executions.tagged("continue_task_priority_test").each { |x| x.terminate }
143
146
  end
144
147
 
145
148
 
@@ -162,13 +165,14 @@ describe "task_priority" do
162
165
  execution.status.should == :continued_as_new
163
166
  events = execution.events.select { |x| x.event_type == "WorkflowExecutionContinuedAsNew" }
164
167
  events.first.attributes.task_priority.should == 100
168
+ @domain.workflow_executions.tagged("continue_task_priority_test").each { |x| x.terminate }
165
169
  end
166
170
  end
167
171
 
168
172
  context "child_workflows" do
169
173
 
170
174
  it "test whether task priority is overridden for child workflow" do
171
- class ChildWorkflowsTestChildWorkflow
175
+ class ChildWorkflowsTaskPriorityTestChildWorkflow
172
176
  extend AWS::Flow::Workflows
173
177
  workflow :child do
174
178
  {
@@ -181,7 +185,7 @@ describe "task_priority" do
181
185
  def child; sleep 1; end
182
186
  end
183
187
 
184
- class ChildWorkflowsTestParentWorkflow
188
+ class ChildWorkflowsTaskPriorityTestParentWorkflow
185
189
  extend AWS::Flow::Workflows
186
190
  workflow :parent do
187
191
  {
@@ -192,15 +196,14 @@ describe "task_priority" do
192
196
  end
193
197
  def parent
194
198
  domain = get_test_domain
195
- client = AWS::Flow::workflow_client(domain.client, domain) { { from_class: "ChildWorkflowsTestChildWorkflow", task_list: "test2" } }
196
- client.send_async(:start_execution)
197
- client.send_async(:start_execution)
199
+ client = AWS::Flow::workflow_client(domain.client, domain) { { from_class: "ChildWorkflowsTaskPriorityTestChildWorkflow", task_list: "test2" } }
200
+ client.start_execution
198
201
  end
199
202
  end
200
203
 
201
- parent_client = AWS::Flow::workflow_client(@domain.client, @domain) { { from_class: "ChildWorkflowsTestParentWorkflow" } }
202
- @child_worker = WorkflowWorker.new(@domain.client, @domain, "test2", ChildWorkflowsTestChildWorkflow)
203
- @parent_worker = WorkflowWorker.new(@domain.client, @domain, "test", ChildWorkflowsTestParentWorkflow)
204
+ parent_client = AWS::Flow::workflow_client(@domain.client, @domain) { { from_class: "ChildWorkflowsTaskPriorityTestParentWorkflow" } }
205
+ @child_worker = WorkflowWorker.new(@domain.client, @domain, "test2", ChildWorkflowsTaskPriorityTestChildWorkflow)
206
+ @parent_worker = WorkflowWorker.new(@domain.client, @domain, "test", ChildWorkflowsTaskPriorityTestParentWorkflow)
204
207
  @child_worker.register
205
208
  @parent_worker.register
206
209
 
@@ -221,4 +224,8 @@ describe "task_priority" do
221
224
 
222
225
  end
223
226
 
227
+ after(:all) do
228
+ Test::Integ.kill_executors
229
+ end
230
+
224
231
  end
@@ -54,20 +54,17 @@ describe "AWS::Flow" do
54
54
  task_list: "bar",
55
55
  version: "2.0",
56
56
  tag_list: ['overriden_test'],
57
- wait: true,
57
+ get_result: true,
58
58
  domain: @domain.name
59
59
  }
60
60
 
61
- executor = ForkingExecutor.new
62
- executor.execute { AWS::Flow::start("StarterTestActivity.foo", {input: "Hello"}, options) }
63
-
64
- executor.shutdown(1)
61
+ future = AWS::Flow::start("StarterTestActivity.foo", {input: "Hello"}, options)
65
62
 
66
63
  until @domain.workflow_executions.count.count > 0
67
64
  sleep 2
68
65
  end
69
66
 
70
- @domain.workflow_executions.each do |x|
67
+ @domain.workflow_executions.tagged("overriden_test").each do |x|
71
68
  x.execution_start_to_close_timeout.should == 100
72
69
  x.workflow_type.name.should == "#{FlowConstants.defaults[:prefix_name]}.#{FlowConstants.defaults[:execution_method]}"
73
70
  x.workflow_type.version.should == "#{FlowConstants.defaults[:version]}"
@@ -82,7 +79,7 @@ describe "AWS::Flow" do
82
79
  root.should be_kind_of(AWS::Flow::Templates::RootTemplate)
83
80
  root.result_step.should_not be_nil
84
81
  result = root.result_step
85
- result.should be_kind_of(AWS::Flow::Templates::ActivityTemplate)
82
+ result.should be_kind_of(AWS::Flow::Templates::ResultActivityTemplate)
86
83
 
87
84
  activity = root.step
88
85
  activity.should be_kind_of(AWS::Flow::Templates::ActivityTemplate)
@@ -100,6 +97,8 @@ describe "AWS::Flow" do
100
97
  x.terminate
101
98
  end
102
99
 
100
+ Test::Integ.kill_executors
101
+
103
102
  end
104
103
 
105
104
  end
@@ -4,9 +4,9 @@ describe "AWS::Flow" do
4
4
 
5
5
  context "#start" do
6
6
 
7
- it "calls AWS::Flow::Templates#start" do
7
+ it "calls AWS::Flow::Templates::Starter#start" do
8
8
  AWS::Flow::stub(:start_workflow)
9
- expect(AWS::Flow::Templates).to receive(:start)
9
+ expect(AWS::Flow::Templates::Starter).to receive(:start)
10
10
  AWS::Flow::start("HelloWorld.hello", { foo: "foo" })
11
11
  end
12
12
 
@@ -180,6 +180,48 @@ end
180
180
 
181
181
  describe ActivityWorker do
182
182
 
183
+ context "#initialize" do
184
+
185
+ context "windows platform" do
186
+
187
+ before(:all) do
188
+ @platform = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
189
+ RbConfig::CONFIG['host_os'] = 'mswin'
190
+ end
191
+
192
+ after(:all) do
193
+ RbConfig::CONFIG['host_os'] = @platform
194
+ end
195
+
196
+ it "turns forking off by default" do
197
+ ActivityWorker.any_instance.stub(:add_implementation)
198
+ worker = AWS::Flow::ActivityWorker.new(nil, nil, "task_list")
199
+ options = worker.instance_variable_get("@options")
200
+ options.use_forking.should be_false
201
+ options.execution_workers.should be_zero
202
+ end
203
+
204
+ it "turns forking on if user explicitely specifies execution workers" do
205
+ ActivityWorker.any_instance.stub(:add_implementation)
206
+ worker = AWS::Flow::ActivityWorker.new(nil, nil, "task_list") { { execution_workers: 5 }}
207
+ options = worker.instance_variable_get("@options")
208
+ options.use_forking.should be_true
209
+ options.execution_workers.should == 5
210
+ end
211
+ end
212
+
213
+ # This test is to ensure that the default behavior of forking is overriden
214
+ # by setting execution_workers to 0. This is added to ensure that forking
215
+ # can be turned off from the json spec for the runner.
216
+ it "turns forking on if execution_workers is 0 and use_forking is true" do
217
+ worker = AWS::Flow::ActivityWorker.new(nil, nil, "task_list") { { execution_workers: 0, use_forking: true }}
218
+ options = worker.instance_variable_get("@options")
219
+ options.use_forking.should be_false
220
+ options.execution_workers.should be_zero
221
+ end
222
+
223
+ end
224
+
183
225
  context "#register" do
184
226
  it "ensures that worker uses the right task list to register type" do
185
227
  class DefaultTasklistTestActivity
@@ -0,0 +1,59 @@
1
+ ##
2
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License").
5
+ # You may not use this file except in compliance with the License.
6
+ # A copy of the License is located at
7
+ #
8
+ # http://aws.amazon.com/apache2.0
9
+ #
10
+ # or in the "license" file accompanying this file. This file is distributed
11
+ # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12
+ # express or implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+ ##
15
+
16
+ require 'spec_helper'
17
+
18
+ describe ExternalConditionVariable do
19
+ let(:condition) { ExternalConditionVariable.new }
20
+
21
+ it "blocks a thread and wakes it up on signal" do
22
+ t = Thread.new { condition.wait }
23
+ sleep 1
24
+ t.status.should == "sleep"
25
+ condition.signal
26
+ t.status.should == false
27
+ end
28
+
29
+ it "blocks multiple threads and wakes one up on signal" do
30
+ t1 = Thread.new { condition.wait }
31
+ t2 = Thread.new { condition.wait }
32
+ sleep 1
33
+ t1.status.should == "sleep"
34
+ t2.status.should == "sleep"
35
+ condition.signal
36
+ (t1.status == false && t2.status == false).should == false
37
+ condition.signal
38
+ (t1.status == false && t2.status == false).should == true
39
+ end
40
+
41
+ it "blocks a thread and wakes it up on broadcast" do
42
+ t = Thread.new { condition.wait }
43
+ sleep 1
44
+ t.status.should == "sleep"
45
+ condition.broadcast
46
+ t.status.should == false
47
+ end
48
+
49
+ it "blocks multiple threads and wakes them up on broadcast" do
50
+ t1 = Thread.new { condition.wait }
51
+ t2 = Thread.new { condition.wait }
52
+ sleep 1
53
+ t1.status.should == "sleep"
54
+ t2.status.should == "sleep"
55
+ condition.broadcast
56
+ (t1.status == false && t2.status == false).should == true
57
+ end
58
+
59
+ end
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  ##
2
4
  # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
5
  #
@@ -208,3 +210,189 @@ describe Future do
208
210
  end
209
211
 
210
212
  end
213
+
214
+ describe ExternalFuture do
215
+ let(:future) { ExternalFuture.new }
216
+ let(:trace) { [] }
217
+ context "#set" do
218
+ it "throws an exception when set multiple times" do
219
+ future.set(:foo)
220
+ expect { future.set(:bar) }.to raise_error AlreadySetException
221
+ end
222
+ end
223
+
224
+ context "#get" do
225
+
226
+ it "returns the value which was set" do
227
+ value = :foo
228
+ future.set(value)
229
+ future.get.should == value
230
+ end
231
+
232
+ it "blocks a thread until a value is ready" do
233
+ future = ExternalFuture.new
234
+
235
+ t1 = Thread.new { future.get }
236
+ sleep 1
237
+ t1.status.should == "sleep"
238
+ future.set
239
+ t1.status.should == false
240
+ end
241
+
242
+ it "works with an already set future" do
243
+ future = ExternalFuture.new.set
244
+ future.get
245
+ # future.get will be a non blocking call if it is already set. If not,
246
+ # then the next line will never be executed
247
+ future.set?.should == true
248
+ end
249
+
250
+ it "blocks multiple threads until a value is ready" do
251
+ future = ExternalFuture.new
252
+ t1 = Thread.new { future.get }
253
+ t2 = Thread.new { future.get }
254
+ t3 = Thread.new { future.get }
255
+
256
+ sleep 1
257
+
258
+ t1.status.should == "sleep"
259
+ t2.status.should == "sleep"
260
+ t3.status.should == "sleep"
261
+
262
+ future.set
263
+
264
+ t1.status.should == false
265
+ t2.status.should == false
266
+ t3.status.should == false
267
+ end
268
+
269
+ context "#timeout" do
270
+ it "raises an exception if timeout occurs and leaves future unset" do
271
+ future = ExternalFuture.new
272
+ expect{future.get(1)}.to raise_error(Timeout::Error)
273
+ future.set?.should == false
274
+ end
275
+
276
+ it "raises an exception if timeout occurs multiple times" do
277
+ future = ExternalFuture.new
278
+ expect{future.get(1)}.to raise_error(Timeout::Error)
279
+ expect{future.get(1)}.to raise_error(Timeout::Error)
280
+ expect{future.get(1)}.to raise_error(Timeout::Error)
281
+ end
282
+
283
+ it "nil timeout will block until the future is set" do
284
+ future = ExternalFuture.new
285
+ t = Thread.new { future.get(nil) }
286
+ sleep 1
287
+ t.status.should == "sleep"
288
+ future.set
289
+ t.status.should == false
290
+ end
291
+
292
+ end
293
+
294
+ end
295
+
296
+ context "#wait_for_any" do
297
+
298
+ it "works with multiple futures" do
299
+ f1 = ExternalFuture.new
300
+ f2 = ExternalFuture.new
301
+ f3 = ExternalFuture.new
302
+ t = Thread.new do
303
+ f1.set("foo")
304
+ end
305
+ r1, r2, r3 = AWS::Flow::Core.wait_for_any(f1, f2, f3)
306
+ r1.get.should == "foo"
307
+ f2.set?.should be_false
308
+ f3.set?.should be_false
309
+ end
310
+
311
+ it "works with no futures" do
312
+ wait_for_any
313
+ # Just need to check if the test completes
314
+ true.should == true
315
+ end
316
+
317
+ it "works with an already set future" do
318
+ future = ExternalFuture.new.set
319
+ wait_for_any(future)
320
+ future.set?.should == true
321
+ end
322
+
323
+ it "works with one set and one unset future" do
324
+ future = ExternalFuture.new.set
325
+ future2 = ExternalFuture.new
326
+ wait_for_any(future, future2)
327
+ future.set?.should == true
328
+ future2.set?.should be_false
329
+ end
330
+
331
+ end
332
+
333
+ context "#wait_for_all" do
334
+
335
+ it "works with multiple futures" do
336
+ f1 = ExternalFuture.new
337
+ f2 = ExternalFuture.new
338
+ f3 = ExternalFuture.new
339
+ t = Thread.new do
340
+ f1.set("foo")
341
+ f2.set("bar")
342
+ f3.set("baz")
343
+ end
344
+ r1, r2, r3 = AWS::Flow::Core.wait_for_all(f1, f2, f3)
345
+ r1.get.should == "foo"
346
+ r2.get.should == "bar"
347
+ r3.get.should == "baz"
348
+ end
349
+
350
+ it "works with no futures" do
351
+ wait_for_all
352
+ # Just need to check if the test completes
353
+ true.should == true
354
+ end
355
+
356
+ it "works with an already set future" do
357
+ future = ExternalFuture.new.set
358
+ wait_for_all(future)
359
+ future.set?.should == true
360
+ end
361
+
362
+ it "works with one set and one unset future" do
363
+ future = ExternalFuture.new.set
364
+ future2 = ExternalFuture.new
365
+ Thread.new { future2.set }
366
+ wait_for_all(future, future2)
367
+ future.set?.should == true
368
+ future2.set?.should == true
369
+ end
370
+
371
+ end
372
+
373
+
374
+ [:timed_wait_for_all, :timed_wait_for_any].each do |method|
375
+
376
+ context "#{method}" do
377
+
378
+ it "raises when timeout expires" do
379
+ future = ExternalFuture.new
380
+ expect { AWS::Flow.send(method, 1, future) }.to raise_error(Timeout::Error)
381
+ end
382
+
383
+ it "doesn't raise when timeout doesn't expires" do
384
+ future = ExternalFuture.new
385
+ Thread.new { sleep 1; future.set }
386
+ expect { AWS::Flow.send(method, 10, future) }.to_not raise_error
387
+ end
388
+
389
+ it "doesn't raise when timeout is nil" do
390
+ future = ExternalFuture.new
391
+ Thread.new { sleep 1; future.set }
392
+ expect { AWS::Flow.send(method, nil, future) }.to_not raise_error
393
+ end
394
+
395
+ end
396
+ end
397
+
398
+ end