aws-flow 2.3.1 → 2.4.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 +8 -8
- data/aws-flow.gemspec +3 -2
- data/bin/aws-flow-ruby +1 -1
- data/bin/aws-flow-utils +5 -0
- data/lib/aws/decider.rb +7 -0
- data/lib/aws/decider/async_retrying_executor.rb +1 -1
- data/lib/aws/decider/data_converter.rb +161 -0
- data/lib/aws/decider/decider.rb +27 -14
- data/lib/aws/decider/flow_defaults.rb +28 -0
- data/lib/aws/decider/implementation.rb +0 -1
- data/lib/aws/decider/options.rb +2 -2
- data/lib/aws/decider/starter.rb +207 -0
- data/lib/aws/decider/task_poller.rb +4 -4
- data/lib/aws/decider/utilities.rb +38 -0
- data/lib/aws/decider/version.rb +1 -1
- data/lib/aws/decider/worker.rb +8 -7
- data/lib/aws/decider/workflow_definition_factory.rb +1 -1
- data/lib/aws/runner.rb +146 -65
- data/lib/aws/templates.rb +4 -0
- data/lib/aws/templates/activity.rb +69 -0
- data/lib/aws/templates/base.rb +87 -0
- data/lib/aws/templates/default.rb +146 -0
- data/lib/aws/templates/starter.rb +256 -0
- data/lib/aws/utils.rb +270 -0
- data/spec/aws/decider/integration/activity_spec.rb +7 -1
- data/spec/aws/decider/integration/data_converter_spec.rb +39 -0
- data/spec/aws/decider/integration/integration_spec.rb +12 -5
- data/spec/aws/decider/integration/options_spec.rb +23 -9
- data/spec/aws/decider/integration/starter_spec.rb +209 -0
- data/spec/aws/decider/unit/data_converter_spec.rb +276 -0
- data/spec/aws/decider/unit/decider_spec.rb +1360 -1386
- data/spec/aws/decider/unit/options_spec.rb +21 -22
- data/spec/aws/decider/unit/retry_spec.rb +8 -0
- data/spec/aws/decider/unit/starter_spec.rb +159 -0
- data/spec/aws/runner/integration/runner_integration_spec.rb +2 -3
- data/spec/aws/runner/unit/runner_unit_spec.rb +128 -38
- data/spec/aws/templates/unit/activity_spec.rb +89 -0
- data/spec/aws/templates/unit/base_spec.rb +72 -0
- data/spec/aws/templates/unit/default_spec.rb +141 -0
- data/spec/aws/templates/unit/starter_spec.rb +271 -0
- data/spec/spec_helper.rb +9 -11
- metadata +41 -4
@@ -16,1569 +16,1543 @@
|
|
16
16
|
require 'yaml'
|
17
17
|
require_relative 'setup'
|
18
18
|
|
19
|
-
describe
|
20
|
-
class MyActivity
|
21
|
-
extend Activity
|
22
|
-
def test_three_arguments(a, b, c)
|
23
|
-
a + b + c
|
24
|
-
end
|
25
|
-
def test_no_arguments()
|
26
|
-
:no_arguments
|
27
|
-
end
|
28
|
-
def test_one_argument(arg)
|
29
|
-
arg
|
30
|
-
end
|
31
|
-
def test_getting_context
|
32
|
-
self.activity_execution_context
|
33
|
-
end
|
34
|
-
activity :test_three_arguments, :test_no_arguments, :test_one_argument
|
35
|
-
end
|
36
|
-
it "ensures that an activity definition can handle one argument" do
|
37
|
-
activity_definition = ActivityDefinition.new(MyActivity.new, :test_one_argument, nil , nil, TrivialConverter.new)
|
38
|
-
activity_definition.execute(5, nil).first.should == 5
|
39
|
-
end
|
40
|
-
it "ensures that you can get the activity context " do
|
41
|
-
activity_definition = ActivityDefinition.new(MyActivity.new, :test_getting_context, nil , nil, TrivialConverter.new)
|
42
|
-
(activity_definition.execute(nil, ActivityExecutionContext.new(nil, nil, nil)).first.is_a? ActivityExecutionContext).should == true
|
43
|
-
end
|
44
|
-
it "ensures that the activity context gets unset after the execute" do
|
45
|
-
activity_definition = ActivityDefinition.new(MyActivity.new, :test_getting_context, nil , nil, TrivialConverter.new)
|
46
|
-
activity_definition.execute(nil, ActivityExecutionContext.new(nil, nil, nil))
|
47
|
-
begin
|
48
|
-
activity_definition.execute(nil, nil)
|
49
|
-
rescue Exception => e
|
50
|
-
e.backtrace.should include "No activity execution context"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
it "ensures that an activity definition can handle multiple arguments" do
|
54
|
-
activity_definition = ActivityDefinition.new(MyActivity.new, :test_three_arguments, nil , nil, TrivialConverter.new)
|
19
|
+
describe "DeciderSpec" do
|
55
20
|
|
56
|
-
|
21
|
+
before(:all) do
|
22
|
+
@bucket = ENV['AWS_SWF_BUCKET_NAME']
|
23
|
+
ENV['AWS_SWF_BUCKET_NAME'] = nil
|
57
24
|
end
|
58
|
-
|
59
|
-
|
60
|
-
activity_definition.execute(nil, nil).first.should == :no_arguments
|
25
|
+
after(:all) do
|
26
|
+
ENV['AWS_SWF_BUCKET_NAME'] = @bucket
|
61
27
|
end
|
62
|
-
end
|
63
28
|
|
64
|
-
describe
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
29
|
+
describe ActivityDefinition do
|
30
|
+
class MyActivity
|
31
|
+
extend Activity
|
32
|
+
def test_three_arguments(a, b, c)
|
33
|
+
a + b + c
|
34
|
+
end
|
35
|
+
def test_no_arguments()
|
70
36
|
:no_arguments
|
71
37
|
end
|
72
|
-
def
|
38
|
+
def test_one_argument(arg)
|
73
39
|
arg
|
74
40
|
end
|
75
|
-
def
|
76
|
-
|
41
|
+
def test_getting_context
|
42
|
+
self.activity_execution_context
|
77
43
|
end
|
78
|
-
|
44
|
+
activity :test_three_arguments, :test_no_arguments, :test_one_argument
|
79
45
|
end
|
80
|
-
|
81
|
-
|
46
|
+
it "ensures that an activity definition can handle one argument" do
|
47
|
+
activity_definition = ActivityDefinition.new(MyActivity.new, :test_one_argument, nil , nil, TrivialConverter.new)
|
48
|
+
activity_definition.execute(5, nil).first.should == 5
|
82
49
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
FlowFiber.stub(:current) { Hash.new(Hash.new) }
|
87
|
-
WorkflowDefinitionFactory.new(MyWorkflow, nil, nil, nil, nil, nil, nil).get_workflow_definition(fake_decision_context) end
|
88
|
-
it "makes sure that workflowDefinitionFactory#get_workflow_definition returns different instances" do
|
89
|
-
FlowFiber.stub(:current) { Hash.new(Hash.new) }
|
90
|
-
workflow_factory = WorkflowDefinitionFactory.new(MyWorkflow, nil, nil, nil, nil, nil ,nil)
|
91
|
-
first_definition = workflow_factory.get_workflow_definition(fake_decision_context)
|
92
|
-
second_definition = workflow_factory.get_workflow_definition(fake_decision_context)
|
93
|
-
(first_definition.object_id == second_definition.object_id).should == false
|
94
|
-
end
|
95
|
-
describe "Testing the input/output" do
|
96
|
-
before(:each) do
|
97
|
-
workflow_definition.converter = TrivialConverter.new
|
50
|
+
it "ensures that you can get the activity context " do
|
51
|
+
activity_definition = ActivityDefinition.new(MyActivity.new, :test_getting_context, nil , nil, TrivialConverter.new)
|
52
|
+
(activity_definition.execute(nil, ActivityExecutionContext.new(nil, nil, nil)).first.is_a? ActivityExecutionContext).should == true
|
98
53
|
end
|
99
|
-
it "ensures that
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
54
|
+
it "ensures that the activity context gets unset after the execute" do
|
55
|
+
activity_definition = ActivityDefinition.new(MyActivity.new, :test_getting_context, nil , nil, TrivialConverter.new)
|
56
|
+
activity_definition.execute(nil, ActivityExecutionContext.new(nil, nil, nil))
|
57
|
+
begin
|
58
|
+
activity_definition.execute(nil, nil)
|
59
|
+
rescue Exception => e
|
60
|
+
e.backtrace.should include "No activity execution context"
|
61
|
+
end
|
104
62
|
end
|
105
|
-
it "ensures that
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end.eventLoop
|
63
|
+
it "ensures that an activity definition can handle multiple arguments" do
|
64
|
+
activity_definition = ActivityDefinition.new(MyActivity.new, :test_three_arguments, nil , nil, TrivialConverter.new)
|
65
|
+
|
66
|
+
activity_definition.execute([1,2,3], nil).first.should == 6
|
110
67
|
end
|
111
|
-
it "ensures that
|
112
|
-
|
113
|
-
|
114
|
-
workflow_definition.execute(5).get.should == 5
|
115
|
-
end.eventLoop
|
68
|
+
it "ensures that an activity definition can handle no arguments" do
|
69
|
+
activity_definition = ActivityDefinition.new(MyActivity.new, :test_no_arguments, nil , nil, TrivialConverter.new)
|
70
|
+
activity_definition.execute(nil, nil).first.should == :no_arguments
|
116
71
|
end
|
117
72
|
end
|
118
|
-
end
|
119
73
|
|
120
|
-
describe
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
Symbol => :test,
|
134
|
-
NilClass => nil,
|
135
|
-
}.each_pair do |klass, exemplar|
|
136
|
-
it "tests #{klass}" do
|
137
|
-
1.upto(10).each do |i|
|
138
|
-
converted_exemplar = exemplar
|
139
|
-
i.times {converted_exemplar = converter.dump converted_exemplar}
|
140
|
-
i.times {converted_exemplar = converter.load converted_exemplar}
|
141
|
-
converted_exemplar.should == exemplar
|
142
|
-
end
|
74
|
+
describe WorkflowDefinitionFactory do
|
75
|
+
before(:each) do
|
76
|
+
class MyWorkflow
|
77
|
+
extend Decider
|
78
|
+
version "1"
|
79
|
+
def no_arguments
|
80
|
+
:no_arguments
|
81
|
+
end
|
82
|
+
def one_argument(arg)
|
83
|
+
arg
|
84
|
+
end
|
85
|
+
def multiple_arguments(arg1, arg2, arg3)
|
86
|
+
arg3
|
143
87
|
end
|
144
|
-
end
|
145
88
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
89
|
+
end
|
90
|
+
class WorkflowDefinition
|
91
|
+
attr_accessor :decision_helper, :workflow_method, :converter
|
92
|
+
end
|
93
|
+
end
|
94
|
+
let(:fake_decision_context) { stub(:decision_helper => nil) }
|
95
|
+
let(:workflow_definition) do
|
96
|
+
FlowFiber.stub(:current) { Hash.new(Hash.new) }
|
97
|
+
WorkflowDefinitionFactory.new(MyWorkflow, nil, nil, nil, nil, nil, nil).get_workflow_definition(fake_decision_context) end
|
98
|
+
it "makes sure that workflowDefinitionFactory#get_workflow_definition returns different instances" do
|
99
|
+
FlowFiber.stub(:current) { Hash.new(Hash.new) }
|
100
|
+
workflow_factory = WorkflowDefinitionFactory.new(MyWorkflow, nil, nil, nil, nil, nil ,nil)
|
101
|
+
first_definition = workflow_factory.get_workflow_definition(fake_decision_context)
|
102
|
+
second_definition = workflow_factory.get_workflow_definition(fake_decision_context)
|
103
|
+
(first_definition.object_id == second_definition.object_id).should == false
|
104
|
+
end
|
105
|
+
describe "Testing the input/output" do
|
106
|
+
before(:each) do
|
107
|
+
workflow_definition.converter = TrivialConverter.new
|
108
|
+
end
|
109
|
+
it "ensures that a workflow definition can handle multiple arguments" do
|
110
|
+
workflow_definition.workflow_method = :multiple_arguments
|
111
|
+
AsyncScope.new do
|
112
|
+
workflow_definition.execute([1, 2, 3]).get
|
113
|
+
end.eventLoop
|
114
|
+
end
|
115
|
+
it "ensures that a workflow definition can handle no arguments" do
|
116
|
+
workflow_definition.workflow_method = :no_arguments
|
117
|
+
AsyncScope.new do
|
118
|
+
workflow_definition.execute(nil).get.should == :no_arguments
|
119
|
+
end.eventLoop
|
120
|
+
end
|
121
|
+
it "ensures that a workflow definition can handle one argument" do
|
122
|
+
workflow_definition.workflow_method = :one_argument
|
123
|
+
AsyncScope.new do
|
124
|
+
workflow_definition.execute(5).get.should == 5
|
125
|
+
end.eventLoop
|
151
126
|
end
|
152
127
|
end
|
153
128
|
end
|
154
|
-
end
|
155
129
|
|
156
|
-
describe Workflows do
|
130
|
+
describe Workflows do
|
157
131
|
|
158
|
-
|
132
|
+
context "#workflow" do
|
159
133
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
134
|
+
it "makes sure we can specify multiple workflows" do
|
135
|
+
class MultipleWorkflowsTest1_Workflow
|
136
|
+
extend AWS::Flow::Workflows
|
137
|
+
workflow :workflow_a do
|
138
|
+
{
|
139
|
+
version: "1.0",
|
140
|
+
default_execution_start_to_close_timeout: 600,
|
141
|
+
default_task_list: "tasklist_a"
|
142
|
+
}
|
143
|
+
end
|
144
|
+
workflow :workflow_b do
|
145
|
+
{
|
146
|
+
version: "1.0",
|
147
|
+
default_execution_start_to_close_timeout: 300,
|
148
|
+
default_task_list: "tasklist_b"
|
149
|
+
}
|
150
|
+
end
|
169
151
|
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
152
|
+
MultipleWorkflowsTest1_Workflow.workflows.count.should == 2
|
153
|
+
MultipleWorkflowsTest1_Workflow.workflows.map(&:name).should == ["MultipleWorkflowsTest1_Workflow.workflow_a", "MultipleWorkflowsTest1_Workflow.workflow_b"]
|
154
|
+
MultipleWorkflowsTest1_Workflow.workflows.map(&:options).map(&:default_task_list).should == ["tasklist_a", "tasklist_b"]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "makes sure we can pass multiple workflow names with same options" do
|
158
|
+
class MultipleWorkflowsTest2_Workflow
|
159
|
+
extend AWS::Flow::Workflows
|
160
|
+
workflow :workflow_a, :workflow_b do
|
161
|
+
{
|
162
|
+
version: "1.0",
|
163
|
+
default_task_list: "tasklist_a"
|
164
|
+
}
|
165
|
+
end
|
176
166
|
end
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
MultipleWorkflowsTest1_Workflow.workflows.map(&:options).map(&:default_task_list).should == ["tasklist_a", "tasklist_b"]
|
181
|
-
end
|
167
|
+
MultipleWorkflowsTest2_Workflow.workflows.count.should == 2
|
168
|
+
MultipleWorkflowsTest2_Workflow.workflows.map(&:name).should == ["MultipleWorkflowsTest2_Workflow.workflow_a", "MultipleWorkflowsTest2_Workflow.workflow_b"]
|
169
|
+
MultipleWorkflowsTest2_Workflow.workflows.map(&:options).map(&:default_task_list).should == ["tasklist_a", "tasklist_a"]
|
182
170
|
|
183
|
-
it "makes sure we can pass multiple workflow names with same options" do
|
184
|
-
class MultipleWorkflowsTest2_Workflow
|
185
|
-
extend AWS::Flow::Workflows
|
186
|
-
workflow :workflow_a, :workflow_b do
|
187
|
-
{
|
188
|
-
version: "1.0",
|
189
|
-
default_task_list: "tasklist_a"
|
190
|
-
}
|
191
|
-
end
|
192
171
|
end
|
193
|
-
MultipleWorkflowsTest2_Workflow.workflows.count.should == 2
|
194
|
-
MultipleWorkflowsTest2_Workflow.workflows.map(&:name).should == ["MultipleWorkflowsTest2_Workflow.workflow_a", "MultipleWorkflowsTest2_Workflow.workflow_b"]
|
195
|
-
MultipleWorkflowsTest2_Workflow.workflows.map(&:options).map(&:default_task_list).should == ["tasklist_a", "tasklist_a"]
|
196
|
-
|
197
172
|
end
|
198
173
|
end
|
199
|
-
end
|
200
174
|
|
201
|
-
describe WorkflowFactory do
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
175
|
+
describe WorkflowFactory do
|
176
|
+
it "ensures that you can create a workflow_client without access to the Workflow definition" do
|
177
|
+
workflow_type_object = double("workflow_type", :name => "NonExistantWorkflow.some_entry_method", :start_execution => "" )
|
178
|
+
domain = FakeDomain.new(workflow_type_object)
|
179
|
+
swf_client = FakeServiceClient.new
|
180
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
181
|
+
options.workflow_name = "NonExistantWorkflow"
|
182
|
+
options.execution_method = "some_entry_method"
|
183
|
+
end
|
184
|
+
# We want to make sure that we get to trying to start the execution on the
|
185
|
+
# workflow_type. The workflow_type will be nil, since we return an empty
|
186
|
+
# array in the domain.
|
187
|
+
my_workflow_factory.get_client.start_execution
|
209
188
|
end
|
210
|
-
# We want to make sure that we get to trying to start the execution on the
|
211
|
-
# workflow_type. The workflow_type will be nil, since we return an empty
|
212
|
-
# array in the domain.
|
213
|
-
my_workflow_factory.get_client.start_execution
|
214
189
|
end
|
215
|
-
end
|
216
190
|
|
217
|
-
describe "FakeHistory" do
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
191
|
+
describe "FakeHistory" do
|
192
|
+
before(:all) do
|
193
|
+
class WorkflowClock
|
194
|
+
alias_method :old_current_time, :current_time
|
195
|
+
def current_time
|
196
|
+
Time.now
|
197
|
+
end
|
223
198
|
end
|
224
199
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
200
|
+
after(:all) do
|
201
|
+
class WorkflowClock
|
202
|
+
alias_method :current_time, :old_current_time
|
203
|
+
end
|
204
|
+
|
229
205
|
end
|
230
206
|
|
231
|
-
end
|
232
207
|
|
208
|
+
it "reproduces a bug found by a customer" do
|
209
|
+
class BadWorkflow
|
210
|
+
class << self
|
211
|
+
attr_accessor :task_list
|
212
|
+
end
|
213
|
+
extend Decider
|
233
214
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
215
|
+
version "1"
|
216
|
+
entry_point :entry_point
|
217
|
+
def entry_point
|
218
|
+
# pass
|
219
|
+
end
|
238
220
|
end
|
239
|
-
|
221
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
222
|
+
domain = FakeDomain.new(workflow_type_object)
|
223
|
+
|
240
224
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
225
|
+
swf_client = FakeServiceClient.new
|
226
|
+
task_list = "BadWorkflow_tasklist"
|
227
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
228
|
+
worker.add_workflow_implementation(BadWorkflow)
|
229
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
230
|
+
options.workflow_name = "BadWorkflow"
|
231
|
+
options.execution_start_to_close_timeout = 3600
|
232
|
+
options.task_list = task_list
|
233
|
+
options.task_start_to_close_timeout = 10
|
234
|
+
options.child_policy = :request_cancel
|
245
235
|
end
|
246
|
-
|
247
|
-
|
248
|
-
domain = FakeDomain.new(workflow_type_object)
|
249
|
-
|
250
|
-
|
251
|
-
swf_client = FakeServiceClient.new
|
252
|
-
task_list = "BadWorkflow_tasklist"
|
253
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
254
|
-
worker.add_workflow_implementation(BadWorkflow)
|
255
|
-
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
256
|
-
options.workflow_name = "BadWorkflow"
|
257
|
-
options.execution_start_to_close_timeout = 3600
|
258
|
-
options.task_list = task_list
|
259
|
-
options.task_start_to_close_timeout = 10
|
260
|
-
options.child_policy = :request_cancel
|
261
|
-
end
|
262
|
-
my_workflow = my_workflow_factory.get_client
|
263
|
-
workflow_execution = my_workflow.start_execution(5)
|
236
|
+
my_workflow = my_workflow_factory.get_client
|
237
|
+
workflow_execution = my_workflow.start_execution(5)
|
264
238
|
|
265
239
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
240
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
241
|
+
def get_decision_task
|
242
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
243
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
244
|
+
[TestHistoryEvent.new("WorkflowExecutionStarted", 1, {:parent_initiated_event_id=>0, :child_policy=>:request_cancel, :execution_start_to_close_timeout=>3600, :task_start_to_close_timeout=>5, :workflow_type=> fake_workflow_type, :task_list=>"BadWorkflow"}),
|
245
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {:parent_initiated_event_id=>0, :child_policy=>:request_cancel, :execution_start_to_close_timeout=>3600, :task_start_to_close_timeout=>5, :workflow_type=> fake_workflow_type, :task_list=>"BadWorkflow"}),
|
246
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {:scheduled_event_id=>2, :identity=>"some_identity"}),
|
247
|
+
TestHistoryEvent.new("DecisionTaskTimedOut", 4, {:scheduled_event_id=>2, :timeout_type=>"START_TO_CLOSE", :started_event_id=>3})
|
248
|
+
])
|
275
249
|
|
250
|
+
end
|
276
251
|
end
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
252
|
+
worker.start
|
253
|
+
# @forking_executor.execute { activity_worker.start }
|
254
|
+
|
255
|
+
# worker.start
|
256
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
257
|
+
"CompleteWorkflowExecution"
|
258
|
+
end
|
259
|
+
|
260
|
+
it "reproduces the ActivityTaskTimedOut problem" do
|
261
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
262
|
+
def get_decision_task
|
263
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.start", "1")
|
264
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
265
|
+
[
|
266
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
267
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
268
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
269
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
270
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
271
|
+
TestHistoryEvent.new("ActivityTaskStarted", 6, {}),
|
272
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
273
|
+
])
|
274
|
+
end
|
300
275
|
end
|
301
|
-
end
|
302
276
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
277
|
+
class BadWorkflow
|
278
|
+
extend AWS::Flow::Workflows
|
279
|
+
workflow :start do
|
280
|
+
{
|
281
|
+
version: "1",
|
282
|
+
default_execution_start_to_close_timeout: 3600,
|
283
|
+
default_task_list: "BadWorkflow_tasklist",
|
284
|
+
default_task_start_to_close_timeout: 10,
|
285
|
+
default_child_policy: :request_cancel
|
286
|
+
}
|
287
|
+
end
|
288
|
+
activity_client(:activity) do
|
289
|
+
{
|
290
|
+
prefix_name: "BadActivity",
|
291
|
+
version: "1",
|
292
|
+
default_task_heartbeat_timeout: "3600",
|
293
|
+
default_task_list: "BadWorkflow",
|
294
|
+
default_task_schedule_to_close_timeout: "30",
|
295
|
+
default_task_schedule_to_start_timeout: "30",
|
296
|
+
default_task_start_to_close_timeout: "10",
|
297
|
+
}
|
298
|
+
end
|
299
|
+
def start
|
300
|
+
activity.run_activity1
|
301
|
+
activity.run_activity2
|
302
|
+
end
|
328
303
|
end
|
329
|
-
|
330
|
-
|
331
|
-
domain = FakeDomain.new(workflow_type_object)
|
304
|
+
workflow_type_object = FakeWorkflowType.new(nil, "BadWorkflow.start", "1.0")
|
305
|
+
domain = FakeDomain.new(workflow_type_object)
|
332
306
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
307
|
+
swf_client = FakeServiceClient.new
|
308
|
+
task_list = "BadWorkflow_tasklist"
|
309
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
310
|
+
worker.add_workflow_implementation(BadWorkflow)
|
311
|
+
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "BadWorkflow" } }
|
338
312
|
|
339
|
-
|
340
|
-
|
313
|
+
workflow_execution = client.start_execution(5)
|
314
|
+
worker.start
|
341
315
|
|
342
|
-
|
343
|
-
|
344
|
-
|
316
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
317
|
+
"FailWorkflowExecution"
|
318
|
+
swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details].should =~
|
345
319
|
/AWS::Flow::ActivityTaskTimedOutException/
|
346
|
-
|
320
|
+
end
|
347
321
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
322
|
+
it "makes sure that exponential retry can take arguments" do
|
323
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
324
|
+
def get_decision_task
|
325
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
326
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
327
|
+
[
|
328
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
329
|
+
])
|
330
|
+
end
|
356
331
|
end
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
332
|
+
class BadWorkflow
|
333
|
+
class << self
|
334
|
+
attr_accessor :task_list
|
335
|
+
end
|
336
|
+
extend Decider
|
337
|
+
version "1"
|
338
|
+
entry_point :entry_point
|
339
|
+
|
340
|
+
activity_client :activity do |options|
|
341
|
+
options.prefix_name = "BadActivity"
|
342
|
+
options.version = "1"
|
343
|
+
options.default_task_heartbeat_timeout = "3600"
|
344
|
+
options.default_task_list = "BadWorkflow"
|
345
|
+
options.default_task_schedule_to_close_timeout = "30"
|
346
|
+
options.default_task_schedule_to_start_timeout = "30"
|
347
|
+
options.default_task_start_to_close_timeout = "10"
|
348
|
+
end
|
349
|
+
def entry_point
|
350
|
+
activity.exponential_retry(:run_activity1, 5) do |o|
|
351
|
+
o.maximum_attempts = 3
|
352
|
+
end
|
353
|
+
end
|
361
354
|
end
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
options.
|
371
|
-
options.
|
372
|
-
options.
|
373
|
-
options.
|
355
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
356
|
+
domain = FakeDomain.new(workflow_type_object)
|
357
|
+
|
358
|
+
swf_client = FakeServiceClient.new
|
359
|
+
task_list = "BadWorkflow_tasklist"
|
360
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
361
|
+
worker.add_workflow_implementation(BadWorkflow)
|
362
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
363
|
+
options.workflow_name = "BadWorkflow"
|
364
|
+
options.execution_start_to_close_timeout = 3600
|
365
|
+
options.task_list = task_list
|
366
|
+
options.task_start_to_close_timeout = 10
|
367
|
+
options.child_policy = :request_cancel
|
368
|
+
end
|
369
|
+
my_workflow = my_workflow_factory.get_client
|
370
|
+
workflow_execution = my_workflow.start_execution
|
371
|
+
worker.start
|
372
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
373
|
+
"ScheduleActivityTask"
|
374
|
+
end
|
375
|
+
|
376
|
+
it "makes sure that overriding works correctly" do
|
377
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
378
|
+
def get_decision_task
|
379
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
380
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
381
|
+
[
|
382
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
383
|
+
])
|
384
|
+
end
|
374
385
|
end
|
375
|
-
|
376
|
-
|
377
|
-
|
386
|
+
class BadWorkflow
|
387
|
+
class << self
|
388
|
+
attr_accessor :task_list
|
389
|
+
end
|
390
|
+
extend Decider
|
391
|
+
version "1"
|
392
|
+
entry_point :entry_point
|
393
|
+
activity_client :activity do |options|
|
394
|
+
options.prefix_name = "BadActivity"
|
395
|
+
options.version = "1"
|
396
|
+
options.default_task_heartbeat_timeout = "3600"
|
397
|
+
options.default_task_list = "BadWorkflow"
|
398
|
+
options.default_task_schedule_to_close_timeout = "30"
|
399
|
+
options.default_task_schedule_to_start_timeout = "30"
|
400
|
+
options.default_task_start_to_close_timeout = "10"
|
401
|
+
end
|
402
|
+
def entry_point
|
403
|
+
activity.exponential_retry(:run_activity1, 5) do |o|
|
404
|
+
o.maximum_attempts = 3
|
405
|
+
end
|
378
406
|
end
|
379
407
|
end
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
408
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
409
|
+
domain = FakeDomain.new(workflow_type_object)
|
410
|
+
|
411
|
+
swf_client = FakeServiceClient.new
|
412
|
+
task_list = "BadWorkflow_tasklist"
|
413
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
414
|
+
worker.add_workflow_implementation(BadWorkflow)
|
415
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
416
|
+
options.workflow_name = "BadWorkflow"
|
417
|
+
options.execution_start_to_close_timeout = 3600
|
418
|
+
options.task_list = task_list
|
419
|
+
options.task_start_to_close_timeout = 10
|
420
|
+
options.child_policy = :request_cancel
|
421
|
+
end
|
422
|
+
my_workflow = my_workflow_factory.get_client
|
423
|
+
workflow_execution = my_workflow.start_execution
|
424
|
+
worker.start
|
425
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
426
|
+
"ScheduleActivityTask"
|
427
|
+
end
|
428
|
+
|
429
|
+
it "makes sure that exponential_retry blocks correctly" do
|
430
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
431
|
+
def get_decision_task
|
432
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
433
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
434
|
+
[
|
435
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
436
|
+
])
|
437
|
+
end
|
410
438
|
end
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
439
|
+
class BadWorkflow
|
440
|
+
class << self
|
441
|
+
attr_accessor :task_list, :trace
|
442
|
+
end
|
443
|
+
@trace = []
|
444
|
+
extend Decider
|
445
|
+
version "1"
|
446
|
+
entry_point :entry_point
|
447
|
+
activity_client :activity do |options|
|
448
|
+
options.prefix_name = "BadActivity"
|
449
|
+
options.version = "1"
|
450
|
+
options.default_task_heartbeat_timeout = "3600"
|
451
|
+
options.default_task_list = "BadWorkflow"
|
452
|
+
options.default_task_schedule_to_close_timeout = "30"
|
453
|
+
options.default_task_schedule_to_start_timeout = "30"
|
454
|
+
options.default_task_start_to_close_timeout = "10"
|
455
|
+
end
|
456
|
+
def entry_point
|
457
|
+
BadWorkflow.trace << :start
|
458
|
+
activity.exponential_retry(:run_activity1, 5) do |o|
|
459
|
+
o.maximum_attempts = 3
|
460
|
+
end
|
461
|
+
BadWorkflow.trace << :middle
|
462
|
+
activity.exponential_retry(:run_activity2, 5) do |o|
|
463
|
+
o.maximum_attempts = 3
|
464
|
+
end
|
465
|
+
activity.run_activity1
|
466
|
+
BadWorkflow.trace << :end
|
431
467
|
end
|
432
468
|
end
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
469
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
470
|
+
domain = FakeDomain.new(workflow_type_object)
|
471
|
+
|
472
|
+
swf_client = FakeServiceClient.new
|
473
|
+
task_list = "BadWorkflow_tasklist"
|
474
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
475
|
+
worker.add_workflow_implementation(BadWorkflow)
|
476
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
477
|
+
options.workflow_name = "BadWorkflow"
|
478
|
+
options.execution_start_to_close_timeout = 3600
|
479
|
+
options.task_list = task_list
|
480
|
+
options.task_start_to_close_timeout = 10
|
481
|
+
options.child_policy = :request_cancel
|
482
|
+
end
|
483
|
+
my_workflow = my_workflow_factory.get_client
|
484
|
+
workflow_execution = my_workflow.start_execution
|
485
|
+
worker.start
|
486
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
487
|
+
"ScheduleActivityTask"
|
488
|
+
BadWorkflow.trace.should == [:start]
|
489
|
+
end
|
490
|
+
|
491
|
+
it "makes sure that exponential_retry blocks correctly when done through configure" do
|
492
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
493
|
+
def get_decision_task
|
494
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
495
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
496
|
+
[
|
497
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
498
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
499
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
500
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
501
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
502
|
+
TestHistoryEvent.new("ActivityTaskStarted", 6, {}),
|
503
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
504
|
+
])
|
505
|
+
end
|
506
|
+
end
|
507
|
+
class BadWorkflow
|
508
|
+
class << self
|
509
|
+
attr_accessor :task_list, :trace
|
510
|
+
end
|
511
|
+
@trace = []
|
512
|
+
extend Decider
|
513
|
+
version "1"
|
514
|
+
entry_point :entry_point
|
515
|
+
activity_client :activity do |options|
|
516
|
+
options.prefix_name = "BadActivity"
|
517
|
+
options.version = "1"
|
518
|
+
options.default_task_heartbeat_timeout = "3600"
|
519
|
+
options.default_task_list = "BadWorkflow"
|
520
|
+
options.default_task_schedule_to_close_timeout = "90"
|
521
|
+
options.default_task_schedule_to_start_timeout = "90"
|
522
|
+
options.default_task_start_to_close_timeout = "90"
|
523
|
+
end
|
524
|
+
def entry_point
|
525
|
+
BadWorkflow.trace << :start
|
454
526
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
527
|
+
activity.reconfigure(:run_activity1) do |o|
|
528
|
+
o.exponential_retry do |retry_options|
|
529
|
+
retry_options.maximum_attempts = 3
|
530
|
+
end
|
531
|
+
end
|
532
|
+
activity.run_activity1
|
533
|
+
BadWorkflow.trace << :middle
|
534
|
+
activity.run_activity1
|
535
|
+
end
|
463
536
|
end
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
options.
|
475
|
-
options.
|
476
|
-
options.
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
537
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
538
|
+
domain = FakeDomain.new(workflow_type_object)
|
539
|
+
|
540
|
+
swf_client = FakeServiceClient.new
|
541
|
+
task_list = "BadWorkflow_tasklist"
|
542
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
543
|
+
worker.add_workflow_implementation(BadWorkflow)
|
544
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
545
|
+
options.workflow_name = "BadWorkflow"
|
546
|
+
options.execution_start_to_close_timeout = 3600
|
547
|
+
options.task_list = task_list
|
548
|
+
options.task_start_to_close_timeout = 30
|
549
|
+
options.child_policy = :request_cancel
|
550
|
+
end
|
551
|
+
my_workflow = my_workflow_factory.get_client
|
552
|
+
workflow_execution = my_workflow.start_execution
|
553
|
+
worker.start
|
554
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
555
|
+
"StartTimer"
|
556
|
+
BadWorkflow.trace.should == [:start]
|
557
|
+
end
|
558
|
+
|
559
|
+
it "makes sure that exponential_retry blocks correctly when done through the activity_client" do
|
560
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
561
|
+
def get_decision_task
|
562
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
563
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
564
|
+
[
|
565
|
+
|
566
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {:created_at => Time.now}),
|
567
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {:created_at => Time.now}),
|
568
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {:created_at => Time.now}),
|
569
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {:created_at => Time.now}),
|
570
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1", :created_at => Time.now}),
|
571
|
+
TestHistoryEvent.new("ActivityTaskStarted", 6, {:created_at => Time.now}),
|
572
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE", :created_at => Time.now}),
|
573
|
+
])
|
574
|
+
end
|
493
575
|
end
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
576
|
+
class BadWorkflow
|
577
|
+
class << self
|
578
|
+
attr_accessor :task_list, :trace
|
579
|
+
end
|
580
|
+
@trace = []
|
581
|
+
extend Decider
|
582
|
+
version "1"
|
583
|
+
entry_point :entry_point
|
584
|
+
activity_client :activity do |options|
|
585
|
+
options.prefix_name = "BadActivity"
|
586
|
+
options.version = "1"
|
587
|
+
options.default_task_heartbeat_timeout = "3600"
|
588
|
+
options.default_task_list = "BadWorkflow"
|
589
|
+
options.default_task_schedule_to_close_timeout = "30"
|
590
|
+
options.default_task_schedule_to_start_timeout = "30"
|
591
|
+
options.default_task_start_to_close_timeout = "30"
|
592
|
+
options.exponential_retry do |retry_options|
|
593
|
+
retry_options.maximum_attempts = 3
|
594
|
+
end
|
595
|
+
end
|
596
|
+
def entry_point
|
597
|
+
BadWorkflow.trace << :start
|
598
|
+
activity.run_activity1
|
599
|
+
BadWorkflow.trace << :middle
|
600
|
+
activity.run_activity1
|
516
601
|
|
517
|
-
|
518
|
-
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
519
|
-
def get_decision_task
|
520
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
521
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
522
|
-
[
|
523
|
-
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
524
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
525
|
-
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
526
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
527
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
528
|
-
TestHistoryEvent.new("ActivityTaskStarted", 6, {}),
|
529
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
530
|
-
])
|
602
|
+
end
|
531
603
|
end
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
options.
|
543
|
-
options.
|
544
|
-
options.
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
604
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
605
|
+
domain = FakeDomain.new(workflow_type_object)
|
606
|
+
|
607
|
+
swf_client = FakeServiceClient.new
|
608
|
+
task_list = "BadWorkflow_tasklist"
|
609
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
610
|
+
worker.add_workflow_implementation(BadWorkflow)
|
611
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
612
|
+
options.workflow_name = "BadWorkflow"
|
613
|
+
options.execution_start_to_close_timeout = 3600
|
614
|
+
options.task_list = task_list
|
615
|
+
options.task_start_to_close_timeout = 30
|
616
|
+
options.child_policy = :request_cancel
|
617
|
+
end
|
618
|
+
my_workflow = my_workflow_factory.get_client
|
619
|
+
workflow_execution = my_workflow.start_execution
|
620
|
+
worker.start
|
621
|
+
|
622
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
623
|
+
"StartTimer"
|
624
|
+
BadWorkflow.trace.should == [:start]
|
625
|
+
end
|
626
|
+
|
627
|
+
it "makes sure that multiple schedules followed by a timeout work" do
|
628
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
629
|
+
def get_decision_task
|
630
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
631
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
632
|
+
[
|
633
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
634
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
635
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
636
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
637
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
638
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 6, {:activity_id => "Activity2"}),
|
639
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 7, {:activity_id => "Activity3"}),
|
640
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 8, {:activity_id => "Activity4"}),
|
641
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 9, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
642
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 10, {:scheduled_event_id => 6, :timeout_type => "START_TO_CLOSE"}),
|
643
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 11, {:scheduled_event_id => 7, :timeout_type => "START_TO_CLOSE"}),
|
644
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 12, {:scheduled_event_id => 8, :timeout_type => "START_TO_CLOSE"}),
|
645
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 13, {}),
|
646
|
+
TestHistoryEvent.new("DecisionTaskStarted", 14, {}),
|
647
|
+
|
648
|
+
])
|
649
|
+
end
|
650
|
+
end
|
651
|
+
class BadWorkflow
|
652
|
+
class << self
|
653
|
+
attr_accessor :task_list, :trace
|
654
|
+
end
|
655
|
+
@trace = []
|
656
|
+
extend Decider
|
657
|
+
version "1"
|
658
|
+
entry_point :entry_point
|
659
|
+
activity_client :activity do |options|
|
660
|
+
options.prefix_name = "BadActivity"
|
661
|
+
options.version = "1"
|
662
|
+
options.default_task_heartbeat_timeout = "3600"
|
663
|
+
options.default_task_list = "BadWorkflow"
|
664
|
+
options.default_task_schedule_to_close_timeout = "30"
|
665
|
+
options.default_task_schedule_to_start_timeout = "30"
|
666
|
+
options.default_task_start_to_close_timeout = "30"
|
667
|
+
options.exponential_retry do |retry_options|
|
555
668
|
retry_options.maximum_attempts = 3
|
556
669
|
end
|
557
670
|
end
|
558
|
-
|
559
|
-
|
560
|
-
|
671
|
+
def entry_point
|
672
|
+
BadWorkflow.trace << :start
|
673
|
+
[:run_activity1, :run_activity2, :run_activity3, :run_activity4].each do |act|
|
674
|
+
activity.send_async(act)
|
675
|
+
end
|
676
|
+
BadWorkflow.trace << :middle
|
677
|
+
activity.run_activity3
|
678
|
+
BadWorkflow.trace << :end
|
679
|
+
end
|
561
680
|
end
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
681
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
682
|
+
domain = FakeDomain.new(workflow_type_object)
|
683
|
+
|
684
|
+
swf_client = FakeServiceClient.new
|
685
|
+
task_list = "BadWorkflow_tasklist"
|
686
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
687
|
+
worker.add_workflow_implementation(BadWorkflow)
|
688
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
689
|
+
options.workflow_name = "BadWorkflow"
|
690
|
+
options.execution_start_to_close_timeout = 3600
|
691
|
+
options.task_list = task_list
|
692
|
+
options.task_start_to_close_timeout = 30
|
693
|
+
options.child_policy = :request_cancel
|
694
|
+
end
|
695
|
+
my_workflow = my_workflow_factory.get_client
|
696
|
+
workflow_execution = my_workflow.start_execution
|
697
|
+
worker.start
|
698
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
699
|
+
"StartTimer"
|
700
|
+
swf_client.trace.first[:decisions].length.should == 4
|
701
|
+
BadWorkflow.trace.should == [:start, :middle]
|
702
|
+
end
|
703
|
+
|
704
|
+
it "makes sure that timeout followed by success is handled correctly" do
|
705
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
706
|
+
def get_decision_task
|
707
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
708
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
709
|
+
[
|
710
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
711
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
712
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
713
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
714
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
715
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 6, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
716
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 7, {}),
|
717
|
+
TestHistoryEvent.new("DecisionTaskStarted", 8, {}),
|
718
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 10, {}),
|
719
|
+
TestHistoryEvent.new("TimerStarted", 11, {:decision_task_completed_event_id => 10, :timer_id => "Timer1", :start_to_fire_timeout => 1}),
|
720
|
+
TestHistoryEvent.new("TimerFired", 12, {:timer_id => "Timer1", :started_event_id => 11}),
|
721
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 13, {}),
|
722
|
+
TestHistoryEvent.new("DecisionTaskStarted", 14, {}),
|
723
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 15, {}),
|
724
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 16, {:activity_id => "Activity2"}),
|
725
|
+
TestHistoryEvent.new("ActivityTaskCompleted", 17, {:scheduled_event_id => 16 }),
|
726
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 18, {}),
|
727
|
+
TestHistoryEvent.new("DecisionTaskStarted", 19, {}),
|
728
|
+
|
729
|
+
])
|
730
|
+
end
|
600
731
|
end
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
end
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
BadWorkflow.trace << :middle
|
626
|
-
activity.run_activity1
|
732
|
+
class BadWorkflow
|
733
|
+
class << self
|
734
|
+
attr_accessor :task_list, :trace
|
735
|
+
end
|
736
|
+
@trace = []
|
737
|
+
extend Decider
|
738
|
+
version "1"
|
739
|
+
entry_point :entry_point
|
740
|
+
activity_client :activity do |options|
|
741
|
+
options.prefix_name = "BadActivity"
|
742
|
+
options.version = "1"
|
743
|
+
options.default_task_heartbeat_timeout = "3600"
|
744
|
+
options.default_task_list = "BadWorkflow"
|
745
|
+
options.default_task_schedule_to_close_timeout = "30"
|
746
|
+
options.default_task_schedule_to_start_timeout = "30"
|
747
|
+
options.default_task_start_to_close_timeout = "30"
|
748
|
+
options.exponential_retry do |retry_options|
|
749
|
+
retry_options.maximum_attempts = 3
|
750
|
+
end
|
751
|
+
end
|
752
|
+
def entry_point
|
753
|
+
BadWorkflow.trace << :start
|
754
|
+
activity.run_activity1
|
755
|
+
BadWorkflow.trace << :middle
|
627
756
|
|
757
|
+
BadWorkflow.trace << :end
|
758
|
+
end
|
628
759
|
end
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 7, {:activity_id => "Activity3"}),
|
666
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 8, {:activity_id => "Activity4"}),
|
667
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 9, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
668
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 10, {:scheduled_event_id => 6, :timeout_type => "START_TO_CLOSE"}),
|
669
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 11, {:scheduled_event_id => 7, :timeout_type => "START_TO_CLOSE"}),
|
670
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 12, {:scheduled_event_id => 8, :timeout_type => "START_TO_CLOSE"}),
|
671
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 13, {}),
|
672
|
-
TestHistoryEvent.new("DecisionTaskStarted", 14, {}),
|
673
|
-
|
674
|
-
])
|
760
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
761
|
+
domain = FakeDomain.new(workflow_type_object)
|
762
|
+
|
763
|
+
swf_client = FakeServiceClient.new
|
764
|
+
task_list = "BadWorkflow_tasklist"
|
765
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
766
|
+
worker.add_workflow_implementation(BadWorkflow)
|
767
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
768
|
+
options.workflow_name = "BadWorkflow"
|
769
|
+
options.execution_start_to_close_timeout = 3600
|
770
|
+
options.task_list = task_list
|
771
|
+
options.task_start_to_close_timeout = 30
|
772
|
+
options.child_policy = :request_cancel
|
773
|
+
end
|
774
|
+
my_workflow = my_workflow_factory.get_client
|
775
|
+
workflow_execution = my_workflow.start_execution
|
776
|
+
worker.start
|
777
|
+
|
778
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
779
|
+
"CompleteWorkflowExecution"
|
780
|
+
BadWorkflow.trace.should == [:start, :middle, :end]
|
781
|
+
end
|
782
|
+
|
783
|
+
it "makes sure that signal works correctly" do
|
784
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
785
|
+
def get_decision_task
|
786
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
787
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
788
|
+
[
|
789
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
790
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
791
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
792
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
793
|
+
TestHistoryEvent.new("WorkflowExecutionSignaled", 5, {:signal_name => "this_signal"}),
|
794
|
+
])
|
795
|
+
end
|
675
796
|
end
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
end
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
797
|
+
class BadWorkflow
|
798
|
+
class << self
|
799
|
+
attr_accessor :task_list, :trace
|
800
|
+
end
|
801
|
+
@trace = []
|
802
|
+
extend Decider
|
803
|
+
version "1"
|
804
|
+
entry_point :entry_point
|
805
|
+
activity_client :activity do |options|
|
806
|
+
options.prefix_name = "BadActivity"
|
807
|
+
options.version = "1"
|
808
|
+
options.default_task_heartbeat_timeout = "3600"
|
809
|
+
options.default_task_list = "BadWorkflow"
|
810
|
+
options.default_task_schedule_to_close_timeout = "30"
|
811
|
+
options.default_task_schedule_to_start_timeout = "30"
|
812
|
+
options.default_task_start_to_close_timeout = "30"
|
813
|
+
options.exponential_retry do |retry_options|
|
814
|
+
retry_options.maximum_attempts = 3
|
815
|
+
end
|
816
|
+
end
|
817
|
+
def this_signal
|
818
|
+
@wait.broadcast
|
819
|
+
end
|
820
|
+
signal :this_signal
|
821
|
+
def entry_point
|
822
|
+
BadWorkflow.trace << :start
|
823
|
+
@wait ||= FiberConditionVariable.new
|
824
|
+
@wait.wait
|
825
|
+
BadWorkflow.trace << :middle
|
826
|
+
BadWorkflow.trace << :end
|
827
|
+
end
|
705
828
|
end
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
738
|
-
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
739
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
740
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
741
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 6, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
742
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 7, {}),
|
743
|
-
TestHistoryEvent.new("DecisionTaskStarted", 8, {}),
|
744
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 10, {}),
|
745
|
-
TestHistoryEvent.new("TimerStarted", 11, {:decision_task_completed_event_id => 10, :timer_id => "Timer1", :start_to_fire_timeout => 1}),
|
746
|
-
TestHistoryEvent.new("TimerFired", 12, {:timer_id => "Timer1", :started_event_id => 11}),
|
747
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 13, {}),
|
748
|
-
TestHistoryEvent.new("DecisionTaskStarted", 14, {}),
|
749
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 15, {}),
|
750
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 16, {:activity_id => "Activity2"}),
|
751
|
-
TestHistoryEvent.new("ActivityTaskCompleted", 17, {:scheduled_event_id => 16 }),
|
752
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 18, {}),
|
753
|
-
TestHistoryEvent.new("DecisionTaskStarted", 19, {}),
|
754
|
-
|
755
|
-
])
|
829
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
830
|
+
domain = FakeDomain.new(workflow_type_object)
|
831
|
+
|
832
|
+
swf_client = FakeServiceClient.new
|
833
|
+
task_list = "BadWorkflow_tasklist"
|
834
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
835
|
+
worker.add_workflow_implementation(BadWorkflow)
|
836
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
837
|
+
options.workflow_name = "BadWorkflow"
|
838
|
+
options.execution_start_to_close_timeout = 3600
|
839
|
+
options.task_list = task_list
|
840
|
+
end
|
841
|
+
my_workflow = my_workflow_factory.get_client
|
842
|
+
workflow_execution = my_workflow.start_execution
|
843
|
+
worker.start
|
844
|
+
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
845
|
+
"CompleteWorkflowExecution"
|
846
|
+
BadWorkflow.trace.should == [:start, :middle, :end]
|
847
|
+
end
|
848
|
+
|
849
|
+
it "makes sure that raising an error properly fails a workflow" do
|
850
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
851
|
+
def get_decision_task
|
852
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
853
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
854
|
+
[
|
855
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
856
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
857
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
858
|
+
])
|
859
|
+
end
|
756
860
|
end
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
options.version = "1"
|
769
|
-
options.default_task_heartbeat_timeout = "3600"
|
770
|
-
options.default_task_list = "BadWorkflow"
|
771
|
-
options.default_task_schedule_to_close_timeout = "30"
|
772
|
-
options.default_task_schedule_to_start_timeout = "30"
|
773
|
-
options.default_task_start_to_close_timeout = "30"
|
774
|
-
options.exponential_retry do |retry_options|
|
775
|
-
retry_options.maximum_attempts = 3
|
776
|
-
end
|
777
|
-
end
|
778
|
-
def entry_point
|
779
|
-
BadWorkflow.trace << :start
|
780
|
-
activity.run_activity1
|
781
|
-
BadWorkflow.trace << :middle
|
782
|
-
|
783
|
-
BadWorkflow.trace << :end
|
861
|
+
class BadWorkflow
|
862
|
+
class << self
|
863
|
+
attr_accessor :task_list, :trace
|
864
|
+
end
|
865
|
+
@trace = []
|
866
|
+
extend Decider
|
867
|
+
version "1"
|
868
|
+
entry_point :entry_point
|
869
|
+
def entry_point
|
870
|
+
raise "This is an expected error"
|
871
|
+
end
|
784
872
|
end
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
TestHistoryEvent.new("WorkflowExecutionSignaled", 5, {:signal_name => "this_signal"}),
|
820
|
-
])
|
873
|
+
workflow_type_object = double("workflow_type", :name => "BadWorkflow.entry_point", :start_execution => "" )
|
874
|
+
domain = FakeDomain.new(workflow_type_object)
|
875
|
+
|
876
|
+
swf_client = FakeServiceClient.new
|
877
|
+
|
878
|
+
task_list = "BadWorkflow_tasklist"
|
879
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, BadWorkflow)
|
880
|
+
|
881
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
882
|
+
options.workflow_name = "BadWorkflow"
|
883
|
+
options.execution_start_to_close_timeout = 3600
|
884
|
+
options.task_list = task_list
|
885
|
+
end
|
886
|
+
my_workflow = my_workflow_factory.get_client
|
887
|
+
workflow_execution = my_workflow.start_execution
|
888
|
+
worker.start
|
889
|
+
swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details].should =~ /This is an expected error/
|
890
|
+
end
|
891
|
+
it "makes sure that you can do retry with the easier Fixnum semantic"do
|
892
|
+
|
893
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
894
|
+
def get_decision_task
|
895
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "FixnumWorkflow.entry_point", "1")
|
896
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
897
|
+
[
|
898
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
899
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
900
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
901
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
902
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
903
|
+
TestHistoryEvent.new("ActivityTaskStarted", 6, {}),
|
904
|
+
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
905
|
+
])
|
906
|
+
end
|
821
907
|
end
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
version "1"
|
830
|
-
entry_point :entry_point
|
831
|
-
activity_client :activity do |options|
|
832
|
-
options.prefix_name = "BadActivity"
|
833
|
-
options.version = "1"
|
834
|
-
options.default_task_heartbeat_timeout = "3600"
|
835
|
-
options.default_task_list = "BadWorkflow"
|
836
|
-
options.default_task_schedule_to_close_timeout = "30"
|
837
|
-
options.default_task_schedule_to_start_timeout = "30"
|
838
|
-
options.default_task_start_to_close_timeout = "30"
|
839
|
-
options.exponential_retry do |retry_options|
|
840
|
-
retry_options.maximum_attempts = 3
|
841
|
-
end
|
842
|
-
end
|
843
|
-
def this_signal
|
844
|
-
@wait.broadcast
|
845
|
-
end
|
846
|
-
signal :this_signal
|
847
|
-
def entry_point
|
848
|
-
BadWorkflow.trace << :start
|
849
|
-
@wait ||= FiberConditionVariable.new
|
850
|
-
@wait.wait
|
851
|
-
BadWorkflow.trace << :middle
|
852
|
-
BadWorkflow.trace << :end
|
908
|
+
workflow_type_object = double("workflow_type", :name => "FixnumWorkflow.entry_point", :start_execution => "" )
|
909
|
+
domain = FakeDomain.new(workflow_type_object)
|
910
|
+
|
911
|
+
class FixnumActivity
|
912
|
+
extend Activity
|
913
|
+
activity :run_activity1
|
914
|
+
def run_activity1; raise StandardError; end
|
853
915
|
end
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
task_list = "BadWorkflow_tasklist"
|
860
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
861
|
-
worker.add_workflow_implementation(BadWorkflow)
|
862
|
-
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
863
|
-
options.workflow_name = "BadWorkflow"
|
864
|
-
options.execution_start_to_close_timeout = 3600
|
865
|
-
options.task_list = task_list
|
866
|
-
end
|
867
|
-
my_workflow = my_workflow_factory.get_client
|
868
|
-
workflow_execution = my_workflow.start_execution
|
869
|
-
worker.start
|
870
|
-
swf_client.trace.first[:decisions].first[:decision_type].should ==
|
871
|
-
"CompleteWorkflowExecution"
|
872
|
-
BadWorkflow.trace.should == [:start, :middle, :end]
|
873
|
-
end
|
916
|
+
class FixnumWorkflow
|
917
|
+
extend Workflows
|
918
|
+
workflow(:entry_point) { {:version => "1"} }
|
919
|
+
activity_client(:activity) { {:version => "1", :prefix_name => "FixnumActivity" } }
|
920
|
+
def entry_point
|
874
921
|
|
875
|
-
|
876
|
-
|
877
|
-
def get_decision_task
|
878
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "BadWorkflow.entry_point", "1")
|
879
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
880
|
-
[
|
881
|
-
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
882
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
883
|
-
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
884
|
-
])
|
922
|
+
activity.retry(:run_activity1, 5) {{:maximum_attempts => 5, :should_jitter => false}}
|
923
|
+
end
|
885
924
|
end
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
925
|
+
swf_client = FakeServiceClient.new
|
926
|
+
task_list = "FixnumWorkflow_tasklist"
|
927
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
928
|
+
options.workflow_name = "FixnumWorkflow"
|
929
|
+
options.execution_start_to_close_timeout = 3600
|
930
|
+
options.task_list = task_list
|
931
|
+
end
|
932
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
933
|
+
worker.add_workflow_implementation(FixnumWorkflow)
|
934
|
+
my_workflow = my_workflow_factory.get_client
|
935
|
+
workflow_execution = my_workflow.start_execution
|
936
|
+
worker.start
|
937
|
+
swf_client.trace.first[:decisions].first[:start_timer_decision_attributes][:start_to_fire_timeout].should == "5"
|
938
|
+
end
|
939
|
+
|
940
|
+
it "ensures that CompleteWorkflowExecutionFailed is correctly handled" do
|
941
|
+
|
942
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
943
|
+
def get_decision_task
|
944
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "CompleteWorkflowExecutionFailedWorkflow.entry_point", "1")
|
945
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
946
|
+
[
|
947
|
+
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
948
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
949
|
+
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
950
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
951
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
952
|
+
TestHistoryEvent.new("ActivityTaskScheduled", 6, {:activity_id => "Activity2"}),
|
953
|
+
TestHistoryEvent.new("ActivityTaskStarted", 7, {}),
|
954
|
+
TestHistoryEvent.new("ActivityTaskFailed", 8, {:scheduled_event_id => 5}),
|
955
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 9, {}),
|
956
|
+
TestHistoryEvent.new("ActivityTaskStarted", 10, {}),
|
957
|
+
TestHistoryEvent.new("ActivityTaskFailed", 11, {:scheduled_event_id => 6}),
|
958
|
+
TestHistoryEvent.new("DecisionTaskStarted", 12, {}),
|
959
|
+
TestHistoryEvent.new("DecisionTaskCompleted", 13, {}),
|
960
|
+
TestHistoryEvent.new("RequestCancelActivityTaskFailed", 14, FakeAttribute.new({:activity_id => "Activity2"}) ) ,
|
961
|
+
TestHistoryEvent.new("CompleteWorkflowExecutionFailed", 15, {}),
|
962
|
+
TestHistoryEvent.new("DecisionTaskScheduled", 16, {}),
|
963
|
+
])
|
964
|
+
end
|
890
965
|
end
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
966
|
+
workflow_type_object = double("workflow_type", :name => "CompleteWorkflowExecutionFailedWorkflow.entry_point", :start_execution => "" )
|
967
|
+
domain = FakeDomain.new(workflow_type_object)
|
968
|
+
|
969
|
+
class CompleteWorkflowExecutionFailedActivity
|
970
|
+
extend Activity
|
971
|
+
activity :run_activity1
|
972
|
+
def run_activity1; raise StandardError; end
|
973
|
+
end
|
974
|
+
class CompleteWorkflowExecutionFailedWorkflow
|
975
|
+
extend Workflows
|
976
|
+
workflow(:entry_point) { {:version => "1"} }
|
977
|
+
activity_client(:activity) { {:version => "1", :prefix_name => "CompleteWorkflowExecutionFailedActivity" } }
|
978
|
+
def entry_point
|
979
|
+
child_futures = []
|
980
|
+
error_handler do |t|
|
981
|
+
t.begin do
|
982
|
+
child_futures << activity.send_async(:run_activity1)
|
983
|
+
child_futures << activity.send_async(:run_activity1)
|
984
|
+
wait_for_all(child_futures)
|
985
|
+
end
|
986
|
+
t.rescue(Exception) do |error|
|
987
|
+
end
|
988
|
+
t.ensure do
|
989
|
+
end
|
990
|
+
end
|
991
|
+
end
|
897
992
|
end
|
898
|
-
|
899
|
-
|
900
|
-
|
993
|
+
swf_client = FakeServiceClient.new
|
994
|
+
task_list = "CompleteWorkflowExecutionFailedWorkflow_tasklist"
|
995
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
996
|
+
options.workflow_name = "CompleteWorkflowExecutionFailedWorkflow"
|
997
|
+
options.execution_start_to_close_timeout = 3600
|
998
|
+
options.task_list = task_list
|
999
|
+
end
|
1000
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
1001
|
+
worker.add_workflow_implementation(CompleteWorkflowExecutionFailedWorkflow)
|
1002
|
+
my_workflow = my_workflow_factory.get_client
|
1003
|
+
workflow_execution = my_workflow.start_execution
|
1004
|
+
worker.start
|
1005
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
it "ensures that time outs do not cause problems" do
|
1009
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1010
|
+
def get_decision_task
|
1011
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "TimeOutWorkflow.entry_point", "1")
|
1012
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1013
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1014
|
+
"DecisionTaskScheduled",
|
1015
|
+
"DecisionTaskStarted",
|
1016
|
+
"DecisionTaskCompleted",
|
1017
|
+
["StartChildWorkflowExecutionInitiated", {:workflow_id => "child_workflow_test"}],
|
1018
|
+
["ChildWorkflowExecutionStarted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1019
|
+
"DecisionTaskScheduled",
|
1020
|
+
"DecisionTaskStarted",
|
1021
|
+
["ChildWorkflowExecutionCompleted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1022
|
+
"DecisionTaskScheduled",
|
1023
|
+
"DecisionTaskTimedOut",
|
1024
|
+
"DecisionTaskStarted",
|
1025
|
+
"DecisionTaskCompleted",
|
1026
|
+
["ActivityTaskScheduled", {:activity_id => "Activity1"}],
|
1027
|
+
"ActivityTaskStarted",
|
1028
|
+
["ActivityTaskCompleted", {:scheduled_event_id => 14}],
|
1029
|
+
"DecisionTaskScheduled",
|
1030
|
+
"DecisionTaskStarted"
|
1031
|
+
]))
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
workflow_type_object = FakeWorkflowType.new(nil, "TimeOutWorkflow.entry_point", "1")
|
901
1035
|
|
902
|
-
|
1036
|
+
domain = FakeDomain.new(workflow_type_object)
|
1037
|
+
swf_client = FakeServiceClient.new
|
1038
|
+
$my_workflow_client = workflow_client(swf_client, domain){{:prefix_name => "TimeOutWorkflow", :execution_method => "entry_point", :version => "1"}}
|
903
1039
|
|
904
|
-
|
905
|
-
|
1040
|
+
class TimeOutActivity
|
1041
|
+
extend Activity
|
1042
|
+
activity :run_activity1
|
1043
|
+
def run_activity1; nil; end
|
1044
|
+
end
|
1045
|
+
class TimeOutWorkflow
|
1046
|
+
extend Workflows
|
1047
|
+
workflow(:entry_point) { {:version => "1"} }
|
1048
|
+
activity_client(:activity) { {:version => "1", :prefix_name => "TimeOutActivity" } }
|
906
1049
|
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
end
|
912
|
-
my_workflow = my_workflow_factory.get_client
|
913
|
-
workflow_execution = my_workflow.start_execution
|
914
|
-
worker.start
|
915
|
-
swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details].should =~ /This is an expected error/
|
916
|
-
end
|
917
|
-
it "makes sure that you can do retry with the easier Fixnum semantic"do
|
918
|
-
|
919
|
-
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
920
|
-
def get_decision_task
|
921
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "FixnumWorkflow.entry_point", "1")
|
922
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
923
|
-
[
|
924
|
-
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
925
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
926
|
-
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
927
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
928
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
929
|
-
TestHistoryEvent.new("ActivityTaskStarted", 6, {}),
|
930
|
-
TestHistoryEvent.new("ActivityTaskTimedOut", 7, {:scheduled_event_id => 5, :timeout_type => "START_TO_CLOSE"}),
|
931
|
-
])
|
1050
|
+
def entry_point
|
1051
|
+
$my_workflow_client.start_execution { { task_list: "nonsense_tasklist", workflow_id: "child_workflow_test" } }
|
1052
|
+
activity_client.run_activity1
|
1053
|
+
end
|
932
1054
|
end
|
933
|
-
end
|
934
|
-
workflow_type_object = double("workflow_type", :name => "FixnumWorkflow.entry_point", :start_execution => "" )
|
935
|
-
domain = FakeDomain.new(workflow_type_object)
|
936
1055
|
|
937
|
-
class FixnumActivity
|
938
|
-
extend Activity
|
939
|
-
activity :run_activity1
|
940
|
-
def run_activity1; raise StandardError; end
|
941
|
-
end
|
942
|
-
class FixnumWorkflow
|
943
|
-
extend Workflows
|
944
|
-
workflow(:entry_point) { {:version => "1"} }
|
945
|
-
activity_client(:activity) { {:version => "1", :prefix_name => "FixnumActivity" } }
|
946
|
-
def entry_point
|
947
1056
|
|
948
|
-
|
1057
|
+
task_list = "TimeOutWorkflow_tasklist"
|
1058
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
1059
|
+
options.workflow_name = "TimeOutWorkflow"
|
1060
|
+
options.execution_start_to_close_timeout = 3600
|
1061
|
+
options.task_list = task_list
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
1065
|
+
worker.add_workflow_implementation(TimeOutWorkflow)
|
1066
|
+
my_workflow = my_workflow_factory.get_client
|
1067
|
+
workflow_execution = my_workflow.start_execution
|
1068
|
+
worker.start
|
1069
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
it "ensures that the other timeout issue is not a problem" do
|
1073
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1074
|
+
def get_decision_task
|
1075
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "OtherTimeOutWorkflow.entry_point", "1")
|
1076
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1077
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1078
|
+
"DecisionTaskScheduled",
|
1079
|
+
"DecisionTaskStarted",
|
1080
|
+
"DecisionTaskCompleted",
|
1081
|
+
["ActivityTaskScheduled", {:activity_id => "Activity1"}],
|
1082
|
+
["ActivityTaskScheduled", {:activity_id => "Activity2"}],
|
1083
|
+
"ActivityTaskStarted",
|
1084
|
+
"ActivityTaskStarted",
|
1085
|
+
["ActivityTaskCompleted", {:scheduled_event_id => 5}],
|
1086
|
+
"DecisionTaskScheduled",
|
1087
|
+
"DecisionTaskStarted",
|
1088
|
+
["ActivityTaskCompleted", {:scheduled_event_id => 6}],
|
1089
|
+
"DecisionTaskScheduled",
|
1090
|
+
"DecisionTaskTimedOut",
|
1091
|
+
"DecisionTaskStarted",
|
1092
|
+
"DecisionTaskCompleted",
|
1093
|
+
["ActivityTaskScheduled", {:activity_id => "Activity3"}],
|
1094
|
+
"ActivityTaskStarted",
|
1095
|
+
["ActivityTaskCompleted", {:scheduled_event_id => 17}],
|
1096
|
+
"DecisionTaskScheduled",
|
1097
|
+
"DecisionTaskStarted"
|
1098
|
+
]))
|
1099
|
+
end
|
949
1100
|
end
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
1101
|
+
workflow_type_object = double("workflow_type", :name => "OtherTimeOutWorkflow.entry_point", :start_execution => "" )
|
1102
|
+
domain = FakeDomain.new(workflow_type_object)
|
1103
|
+
swf_client = FakeServiceClient.new
|
1104
|
+
$my_workflow_client = workflow_client(swf_client, domain) {{:prefix_name => "OtherTimeOutWorkflow", :execution_method => "entry_point", :version => "1"}}
|
1105
|
+
class OtherTimeOutActivity
|
1106
|
+
extend Activity
|
1107
|
+
activity :run_activity1
|
1108
|
+
def run_activity1; nil; end
|
1109
|
+
end
|
1110
|
+
class OtherTimeOutWorkflow
|
1111
|
+
extend Workflows
|
1112
|
+
workflow(:entry_point) { {:version => "1"} }
|
1113
|
+
activity_client(:activity) { {:version => "1", :prefix_name => "OtherTimeOutActivity" } }
|
1114
|
+
|
1115
|
+
def entry_point
|
1116
|
+
futures = []
|
1117
|
+
futures << activity_client.send_async(:run_activity1)
|
1118
|
+
futures << activity_client.send_async(:run_activity1)
|
1119
|
+
wait_for_all(futures)
|
1120
|
+
activity_client.run_activity1
|
1121
|
+
end
|
965
1122
|
|
966
|
-
it "ensures that CompleteWorkflowExecutionFailed is correctly handled" do
|
967
|
-
|
968
|
-
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
969
|
-
def get_decision_task
|
970
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "CompleteWorkflowExecutionFailedWorkflow.entry_point", "1")
|
971
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
972
|
-
[
|
973
|
-
TestHistoryEvent.new("WorkflowExecutionStarted", 1, {}),
|
974
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 2, {}),
|
975
|
-
TestHistoryEvent.new("DecisionTaskStarted", 3, {}),
|
976
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 4, {}),
|
977
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 5, {:activity_id => "Activity1"}),
|
978
|
-
TestHistoryEvent.new("ActivityTaskScheduled", 6, {:activity_id => "Activity2"}),
|
979
|
-
TestHistoryEvent.new("ActivityTaskStarted", 7, {}),
|
980
|
-
TestHistoryEvent.new("ActivityTaskFailed", 8, {:scheduled_event_id => 5}),
|
981
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 9, {}),
|
982
|
-
TestHistoryEvent.new("ActivityTaskStarted", 10, {}),
|
983
|
-
TestHistoryEvent.new("ActivityTaskFailed", 11, {:scheduled_event_id => 6}),
|
984
|
-
TestHistoryEvent.new("DecisionTaskStarted", 12, {}),
|
985
|
-
TestHistoryEvent.new("DecisionTaskCompleted", 13, {}),
|
986
|
-
TestHistoryEvent.new("RequestCancelActivityTaskFailed", 14, FakeAttribute.new({:activity_id => "Activity2"}) ) ,
|
987
|
-
TestHistoryEvent.new("CompleteWorkflowExecutionFailed", 15, {}),
|
988
|
-
TestHistoryEvent.new("DecisionTaskScheduled", 16, {}),
|
989
|
-
])
|
990
1123
|
end
|
991
|
-
end
|
992
|
-
workflow_type_object = double("workflow_type", :name => "CompleteWorkflowExecutionFailedWorkflow.entry_point", :start_execution => "" )
|
993
|
-
domain = FakeDomain.new(workflow_type_object)
|
994
1124
|
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
1125
|
+
task_list = "OtherTimeOutWorkflow_tasklist"
|
1126
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
1127
|
+
options.workflow_name = "OtherTimeOutWorkflow"
|
1128
|
+
options.execution_start_to_close_timeout = 3600
|
1129
|
+
options.task_list = task_list
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
1133
|
+
worker.add_workflow_implementation(OtherTimeOutWorkflow)
|
1134
|
+
my_workflow = my_workflow_factory.get_client
|
1135
|
+
workflow_execution = my_workflow.start_execution
|
1136
|
+
worker.start
|
1137
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
999
1138
|
end
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1139
|
+
|
1140
|
+
it "replicates the error seen in github issue #37" do
|
1141
|
+
|
1142
|
+
class TimeOutFailuresWorkflow
|
1143
|
+
extend Workflows
|
1144
|
+
workflow(:entry_point) do
|
1145
|
+
{
|
1146
|
+
execution_start_to_close_timeout: 600,
|
1147
|
+
task_list: "TimeOutFailuresWorkflow_tasklist",
|
1148
|
+
version: "1.0",
|
1149
|
+
}
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
def entry_point
|
1153
|
+
error_handler do |t|
|
1154
|
+
t.begin do
|
1155
|
+
$client.send_async(:start_execution) { {task_list: "nonsense_task_list", workflow_id: "child_workflow_test"}}
|
1156
|
+
create_timer(5)
|
1157
|
+
end
|
1158
|
+
t.rescue AWS::Flow::ChildWorkflowException do |ex|
|
1159
|
+
# noop because we don't want the parent execution to die
|
1160
|
+
end
|
1015
1161
|
end
|
1016
1162
|
end
|
1017
1163
|
end
|
1018
|
-
end
|
1019
|
-
swf_client = FakeServiceClient.new
|
1020
|
-
task_list = "CompleteWorkflowExecutionFailedWorkflow_tasklist"
|
1021
|
-
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
1022
|
-
options.workflow_name = "CompleteWorkflowExecutionFailedWorkflow"
|
1023
|
-
options.execution_start_to_close_timeout = 3600
|
1024
|
-
options.task_list = task_list
|
1025
|
-
end
|
1026
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
1027
|
-
worker.add_workflow_implementation(CompleteWorkflowExecutionFailedWorkflow)
|
1028
|
-
my_workflow = my_workflow_factory.get_client
|
1029
|
-
workflow_execution = my_workflow.start_execution
|
1030
|
-
worker.start
|
1031
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1032
|
-
end
|
1033
1164
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1165
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1166
|
+
def get_decision_task
|
1167
|
+
TestHistoryWrapper.new($workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1168
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1169
|
+
"DecisionTaskScheduled",
|
1170
|
+
"DecisionTaskStarted",
|
1171
|
+
"DecisionTaskCompleted",
|
1172
|
+
["TimerStarted", {:decision_task_completed_event_id => 4, :timer_id => "Timer1", :start_to_fire_timeout => 10}],
|
1173
|
+
["StartChildWorkflowExecutionInitiated", {:workflow_id => "child_workflow_test"}],
|
1174
|
+
["ChildWorkflowExecutionStarted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1175
|
+
|
1176
|
+
"DecisionTaskScheduled",
|
1177
|
+
"DecisionTaskStarted",
|
1178
|
+
"DecisionTaskCompleted",
|
1179
|
+
["ChildWorkflowExecutionTerminated", :workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test")],
|
1180
|
+
"DecisionTaskScheduled",
|
1181
|
+
"DecisionTaskStarted",
|
1182
|
+
["TimerFired", {:timer_id => "Timer1"}],
|
1183
|
+
"DecisionTaskScheduled",
|
1184
|
+
"DecisionTaskCompleted",
|
1185
|
+
["CancelTimerFailed", {:timer_id => "Timer1"}],
|
1186
|
+
"CompleteWorkflowExecutionFailed",
|
1187
|
+
"DecisionTaskScheduled",
|
1188
|
+
"DecisionTaskStarted"
|
1189
|
+
]))
|
1190
|
+
end
|
1058
1191
|
end
|
1059
|
-
end
|
1060
|
-
workflow_type_object = FakeWorkflowType.new(nil, "TimeOutWorkflow.entry_point", "1")
|
1061
|
-
|
1062
|
-
domain = FakeDomain.new(workflow_type_object)
|
1063
|
-
swf_client = FakeServiceClient.new
|
1064
|
-
$my_workflow_client = workflow_client(swf_client, domain){{:prefix_name => "TimeOutWorkflow", :execution_method => "entry_point", :version => "1"}}
|
1065
1192
|
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
end
|
1071
|
-
class TimeOutWorkflow
|
1072
|
-
extend Workflows
|
1073
|
-
workflow(:entry_point) { {:version => "1"} }
|
1074
|
-
activity_client(:activity) { {:version => "1", :prefix_name => "TimeOutActivity" } }
|
1193
|
+
$workflow_type = FakeWorkflowType.new(nil, "TimeOutFailuresWorkflow.entry_point", "1.0")
|
1194
|
+
swf_client = FakeServiceClient.new
|
1195
|
+
domain = FakeDomain.new($workflow_type)
|
1196
|
+
$client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "TimeOutFailuresWorkflow" } }
|
1075
1197
|
|
1076
|
-
|
1077
|
-
|
1078
|
-
activity_client.run_activity1
|
1198
|
+
task_list = "TimeOutFailuresWorkflow_tasklist"
|
1199
|
+
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
1079
1200
|
end
|
1080
|
-
end
|
1081
1201
|
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1202
|
+
$client.start_execution
|
1203
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, TimeOutFailuresWorkflow)
|
1204
|
+
worker.start
|
1205
|
+
#my_workflow = my_workflow_factory.get_client
|
1206
|
+
#workflow_execution = my_workflow.start_execution
|
1207
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1088
1208
|
end
|
1089
1209
|
|
1090
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list)
|
1091
|
-
worker.add_workflow_implementation(TimeOutWorkflow)
|
1092
|
-
my_workflow = my_workflow_factory.get_client
|
1093
|
-
workflow_execution = my_workflow.start_execution
|
1094
|
-
worker.start
|
1095
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1096
1210
|
end
|
1097
1211
|
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1103
|
-
FakeEvents.new(["WorkflowExecutionStarted",
|
1104
|
-
"DecisionTaskScheduled",
|
1105
|
-
"DecisionTaskStarted",
|
1106
|
-
"DecisionTaskCompleted",
|
1107
|
-
["ActivityTaskScheduled", {:activity_id => "Activity1"}],
|
1108
|
-
["ActivityTaskScheduled", {:activity_id => "Activity2"}],
|
1109
|
-
"ActivityTaskStarted",
|
1110
|
-
"ActivityTaskStarted",
|
1111
|
-
["ActivityTaskCompleted", {:scheduled_event_id => 5}],
|
1112
|
-
"DecisionTaskScheduled",
|
1113
|
-
"DecisionTaskStarted",
|
1114
|
-
["ActivityTaskCompleted", {:scheduled_event_id => 6}],
|
1115
|
-
"DecisionTaskScheduled",
|
1116
|
-
"DecisionTaskTimedOut",
|
1117
|
-
"DecisionTaskStarted",
|
1118
|
-
"DecisionTaskCompleted",
|
1119
|
-
["ActivityTaskScheduled", {:activity_id => "Activity3"}],
|
1120
|
-
"ActivityTaskStarted",
|
1121
|
-
["ActivityTaskCompleted", {:scheduled_event_id => 17}],
|
1122
|
-
"DecisionTaskScheduled",
|
1123
|
-
"DecisionTaskStarted"
|
1124
|
-
]))
|
1125
|
-
end
|
1126
|
-
end
|
1127
|
-
workflow_type_object = double("workflow_type", :name => "OtherTimeOutWorkflow.entry_point", :start_execution => "" )
|
1128
|
-
domain = FakeDomain.new(workflow_type_object)
|
1129
|
-
swf_client = FakeServiceClient.new
|
1130
|
-
$my_workflow_client = workflow_client(swf_client, domain) {{:prefix_name => "OtherTimeOutWorkflow", :execution_method => "entry_point", :version => "1"}}
|
1131
|
-
class OtherTimeOutActivity
|
1132
|
-
extend Activity
|
1133
|
-
activity :run_activity1
|
1134
|
-
def run_activity1; nil; end
|
1135
|
-
end
|
1136
|
-
class OtherTimeOutWorkflow
|
1137
|
-
extend Workflows
|
1138
|
-
workflow(:entry_point) { {:version => "1"} }
|
1139
|
-
activity_client(:activity) { {:version => "1", :prefix_name => "OtherTimeOutActivity" } }
|
1140
|
-
|
1141
|
-
def entry_point
|
1142
|
-
futures = []
|
1143
|
-
futures << activity_client.send_async(:run_activity1)
|
1144
|
-
futures << activity_client.send_async(:run_activity1)
|
1145
|
-
wait_for_all(futures)
|
1146
|
-
activity_client.run_activity1
|
1212
|
+
describe "Misc tests" do
|
1213
|
+
it "makes sure that Workflows is equivalent to Decider" do
|
1214
|
+
class TestDecider
|
1215
|
+
extend Workflows
|
1147
1216
|
end
|
1148
|
-
|
1217
|
+
TestDecider.methods.map(&:to_sym).should include :signal
|
1149
1218
|
end
|
1150
1219
|
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
options.task_list = task_list
|
1220
|
+
it "ensures you can eager_autoload" do
|
1221
|
+
require 'aws'
|
1222
|
+
require 'aws/decider'
|
1223
|
+
AWS.eager_autoload!
|
1156
1224
|
end
|
1157
1225
|
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
it "replicates the error seen in github issue #37" do
|
1167
|
-
|
1168
|
-
class TimeOutFailuresWorkflow
|
1169
|
-
extend Workflows
|
1170
|
-
workflow(:entry_point) do
|
1171
|
-
{
|
1172
|
-
execution_start_to_close_timeout: 600,
|
1173
|
-
task_list: "TimeOutFailuresWorkflow_tasklist",
|
1174
|
-
version: "1.0",
|
1175
|
-
}
|
1226
|
+
it "ensures that using send_async doesn't mutate the original hash" do
|
1227
|
+
class GenericClientTest < GenericClient
|
1228
|
+
def call_options(*args, &options)
|
1229
|
+
options.call
|
1230
|
+
end
|
1176
1231
|
end
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
end
|
1184
|
-
t.rescue AWS::Flow::ChildWorkflowException do |ex|
|
1185
|
-
# noop because we don't want the parent execution to die
|
1232
|
+
# Instead of setting up the fiber, just pretend we're internal
|
1233
|
+
module Utilities
|
1234
|
+
class << self
|
1235
|
+
alias_method :old_is_external, :is_external
|
1236
|
+
def is_external
|
1237
|
+
return false
|
1186
1238
|
end
|
1187
1239
|
end
|
1188
1240
|
end
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
["TimerStarted", {:decision_task_completed_event_id => 4, :timer_id => "Timer1", :start_to_fire_timeout => 10}],
|
1199
|
-
["StartChildWorkflowExecutionInitiated", {:workflow_id => "child_workflow_test"}],
|
1200
|
-
["ChildWorkflowExecutionStarted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1201
|
-
|
1202
|
-
"DecisionTaskScheduled",
|
1203
|
-
"DecisionTaskStarted",
|
1204
|
-
"DecisionTaskCompleted",
|
1205
|
-
["ChildWorkflowExecutionTerminated", :workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test")],
|
1206
|
-
"DecisionTaskScheduled",
|
1207
|
-
"DecisionTaskStarted",
|
1208
|
-
["TimerFired", {:timer_id => "Timer1"}],
|
1209
|
-
"DecisionTaskScheduled",
|
1210
|
-
"DecisionTaskCompleted",
|
1211
|
-
["CancelTimerFailed", {:timer_id => "Timer1"}],
|
1212
|
-
"CompleteWorkflowExecutionFailed",
|
1213
|
-
"DecisionTaskScheduled",
|
1214
|
-
"DecisionTaskStarted"
|
1215
|
-
]))
|
1241
|
+
generic_client = GenericClientTest.new
|
1242
|
+
previous_hash = {:key => :value}
|
1243
|
+
previous_hash_copy = previous_hash.dup
|
1244
|
+
generic_client.send_async(:call_options) { previous_hash }
|
1245
|
+
# Put is_external back before we have a chance of failing
|
1246
|
+
module Utilities
|
1247
|
+
class << self
|
1248
|
+
alias_method :is_external, :old_is_external
|
1249
|
+
end
|
1216
1250
|
end
|
1251
|
+
previous_hash.should == previous_hash_copy
|
1217
1252
|
end
|
1218
|
-
|
1219
|
-
$workflow_type = FakeWorkflowType.new(nil, "TimeOutFailuresWorkflow.entry_point", "1.0")
|
1220
|
-
swf_client = FakeServiceClient.new
|
1221
|
-
domain = FakeDomain.new($workflow_type)
|
1222
|
-
$client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "TimeOutFailuresWorkflow" } }
|
1223
|
-
|
1224
|
-
task_list = "TimeOutFailuresWorkflow_tasklist"
|
1225
|
-
my_workflow_factory = workflow_factory(swf_client, domain) do |options|
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
$client.start_execution
|
1229
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, TimeOutFailuresWorkflow)
|
1230
|
-
worker.start
|
1231
|
-
#my_workflow = my_workflow_factory.get_client
|
1232
|
-
#workflow_execution = my_workflow.start_execution
|
1233
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "CompleteWorkflowExecution"
|
1234
|
-
end
|
1235
|
-
|
1236
|
-
end
|
1237
1253
|
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1254
|
+
it "makes sure complete method is present on the completion handle and not open request" do
|
1255
|
+
( OpenRequestInfo.new.respond_to? :complete ).should == false
|
1256
|
+
task = ExternalTask.new({}) { |t| }
|
1257
|
+
( ExternalTaskCompletionHandle.new(task).respond_to? :complete ).should == true
|
1242
1258
|
end
|
1243
|
-
TestDecider.methods.map(&:to_sym).should include :signal
|
1244
1259
|
end
|
1245
1260
|
|
1246
|
-
|
1247
|
-
|
1248
|
-
require 'aws/decider'
|
1249
|
-
AWS.eager_autoload!
|
1250
|
-
end
|
1261
|
+
describe "Workflow/Activity return values/exceptions" do
|
1262
|
+
it "ensures that a workflow exception message > 32k fails the workflow correctly and truncates the message" do
|
1251
1263
|
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
module Utilities
|
1260
|
-
class << self
|
1261
|
-
alias_method :old_is_external, :is_external
|
1262
|
-
def is_external
|
1263
|
-
return false
|
1264
|
+
class WorkflowOutputTooLarge
|
1265
|
+
extend Workflows
|
1266
|
+
workflow(:entry_point) do
|
1267
|
+
{
|
1268
|
+
version: "1.0",
|
1269
|
+
default_execution_start_to_close_timeout: 600,
|
1270
|
+
}
|
1264
1271
|
end
|
1265
|
-
end
|
1266
|
-
end
|
1267
|
-
generic_client = GenericClientTest.new
|
1268
|
-
previous_hash = {:key => :value}
|
1269
|
-
previous_hash_copy = previous_hash.dup
|
1270
|
-
generic_client.send_async(:call_options) { previous_hash }
|
1271
|
-
# Put is_external back before we have a chance of failing
|
1272
|
-
module Utilities
|
1273
|
-
class << self
|
1274
|
-
alias_method :is_external, :old_is_external
|
1275
|
-
end
|
1276
|
-
end
|
1277
|
-
previous_hash.should == previous_hash_copy
|
1278
|
-
end
|
1279
1272
|
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
( ExternalTaskCompletionHandle.new(task).respond_to? :complete ).should == true
|
1284
|
-
end
|
1285
|
-
end
|
1286
|
-
|
1287
|
-
describe "Workflow/Activity return values/exceptions" do
|
1288
|
-
it "ensures that a workflow exception message > 32k fails the workflow correctly and truncates the message" do
|
1289
|
-
|
1290
|
-
class WorkflowOutputTooLarge
|
1291
|
-
extend Workflows
|
1292
|
-
workflow(:entry_point) do
|
1293
|
-
{
|
1294
|
-
version: "1.0",
|
1295
|
-
default_execution_start_to_close_timeout: 600,
|
1296
|
-
}
|
1273
|
+
def entry_point
|
1274
|
+
raise "a"*33000
|
1275
|
+
end
|
1297
1276
|
end
|
1298
1277
|
|
1299
|
-
|
1300
|
-
|
1278
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1279
|
+
def get_decision_task
|
1280
|
+
TestHistoryWrapper.new($workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1281
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1282
|
+
"DecisionTaskScheduled",
|
1283
|
+
"DecisionTaskStarted",
|
1284
|
+
]))
|
1285
|
+
end
|
1301
1286
|
end
|
1302
|
-
end
|
1303
1287
|
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
"DecisionTaskScheduled",
|
1309
|
-
"DecisionTaskStarted",
|
1310
|
-
]))
|
1311
|
-
end
|
1312
|
-
end
|
1288
|
+
$workflow_type = FakeWorkflowType.new(nil, "WorkflowOutputTooLarge.entry_point", "1.0")
|
1289
|
+
swf_client = FakeServiceClient.new
|
1290
|
+
domain = FakeDomain.new($workflow_type)
|
1291
|
+
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1313
1292
|
|
1314
|
-
|
1315
|
-
swf_client = FakeServiceClient.new
|
1316
|
-
domain = FakeDomain.new($workflow_type)
|
1317
|
-
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1293
|
+
task_list = "WorkflowsOutputTooLarge"
|
1318
1294
|
|
1319
|
-
|
1295
|
+
client.start_execution
|
1296
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, WorkflowOutputTooLarge)
|
1297
|
+
worker.start
|
1320
1298
|
|
1321
|
-
|
1322
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, WorkflowOutputTooLarge)
|
1323
|
-
worker.start
|
1299
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1324
1300
|
|
1325
|
-
|
1301
|
+
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1302
|
+
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1303
|
+
reason.should include("TRUNCATED")
|
1304
|
+
exception = FlowConstants.data_converter.load(details)
|
1305
|
+
exception.class.should == RuntimeError
|
1306
|
+
exception.message.should == "a"*245+"[TRUNCATED]"
|
1307
|
+
end
|
1326
1308
|
|
1327
|
-
|
1328
|
-
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1329
|
-
reason.should include("TRUNCATED")
|
1330
|
-
exception = FlowConstants.default_data_converter.load(details)
|
1331
|
-
exception.class.should == RuntimeError
|
1332
|
-
exception.message.should == "a"*245+"[TRUNCATED]"
|
1333
|
-
end
|
1309
|
+
it "ensures that a workflow backtrace > 32k fails the workflow correctly and truncates the backtrace" do
|
1334
1310
|
|
1335
|
-
|
1311
|
+
class WorkflowOutputTooLarge
|
1312
|
+
extend Workflows
|
1313
|
+
workflow(:entry_point) do
|
1314
|
+
{
|
1315
|
+
version: "1.0",
|
1316
|
+
default_execution_start_to_close_timeout: 600,
|
1317
|
+
}
|
1318
|
+
end
|
1336
1319
|
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
default_execution_start_to_close_timeout: 600,
|
1343
|
-
}
|
1320
|
+
def entry_point
|
1321
|
+
a = StandardError.new("SIMULATION")
|
1322
|
+
a.set_backtrace("a"*33000)
|
1323
|
+
raise a
|
1324
|
+
end
|
1344
1325
|
end
|
1345
1326
|
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1327
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1328
|
+
def get_decision_task
|
1329
|
+
TestHistoryWrapper.new($workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1330
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1331
|
+
"DecisionTaskScheduled",
|
1332
|
+
"DecisionTaskStarted",
|
1333
|
+
]))
|
1334
|
+
end
|
1350
1335
|
end
|
1351
|
-
end
|
1352
1336
|
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
"DecisionTaskScheduled",
|
1358
|
-
"DecisionTaskStarted",
|
1359
|
-
]))
|
1360
|
-
end
|
1361
|
-
end
|
1337
|
+
$workflow_type = FakeWorkflowType.new(nil, "WorkflowOutputTooLarge.entry_point", "1.0")
|
1338
|
+
swf_client = FakeServiceClient.new
|
1339
|
+
domain = FakeDomain.new($workflow_type)
|
1340
|
+
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1362
1341
|
|
1363
|
-
|
1364
|
-
swf_client = FakeServiceClient.new
|
1365
|
-
domain = FakeDomain.new($workflow_type)
|
1366
|
-
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1342
|
+
task_list = "WorkflowsOutputTooLarge"
|
1367
1343
|
|
1368
|
-
|
1344
|
+
client.start_execution
|
1345
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, WorkflowOutputTooLarge)
|
1346
|
+
worker.start
|
1369
1347
|
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1348
|
+
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1349
|
+
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1350
|
+
exception = FlowConstants.data_converter.load(details)
|
1351
|
+
exception.class.should == StandardError
|
1352
|
+
exception.message.should == "SIMULATION"
|
1353
|
+
exception.backtrace.first.should include("[TRUNCATED]")
|
1354
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1355
|
+
end
|
1373
1356
|
|
1374
|
-
|
1375
|
-
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1376
|
-
exception = FlowConstants.default_data_converter.load(details)
|
1377
|
-
exception.class.should == StandardError
|
1378
|
-
exception.message.should == "SIMULATION"
|
1379
|
-
exception.backtrace.first.should include("[TRUNCATED]")
|
1380
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1381
|
-
end
|
1357
|
+
it "ensures that a workflow output > 32k fails the workflow correctly" do
|
1382
1358
|
|
1383
|
-
|
1359
|
+
class WorkflowOutputTooLarge
|
1360
|
+
extend Workflows
|
1361
|
+
workflow(:entry_point) do
|
1362
|
+
{
|
1363
|
+
version: "1.0",
|
1364
|
+
default_execution_start_to_close_timeout: 600,
|
1365
|
+
}
|
1366
|
+
end
|
1384
1367
|
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
{
|
1389
|
-
version: "1.0",
|
1390
|
-
default_execution_start_to_close_timeout: 600,
|
1391
|
-
}
|
1368
|
+
def entry_point
|
1369
|
+
return "a"*33000
|
1370
|
+
end
|
1392
1371
|
end
|
1393
1372
|
|
1394
|
-
|
1395
|
-
|
1373
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1374
|
+
def get_decision_task
|
1375
|
+
TestHistoryWrapper.new($workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1376
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1377
|
+
"DecisionTaskScheduled",
|
1378
|
+
"DecisionTaskStarted",
|
1379
|
+
]))
|
1380
|
+
end
|
1396
1381
|
end
|
1397
|
-
end
|
1398
1382
|
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
"DecisionTaskScheduled",
|
1404
|
-
"DecisionTaskStarted",
|
1405
|
-
]))
|
1406
|
-
end
|
1407
|
-
end
|
1383
|
+
$workflow_type = FakeWorkflowType.new(nil, "WorkflowOutputTooLarge.entry_point", "1.0")
|
1384
|
+
swf_client = FakeServiceClient.new
|
1385
|
+
domain = FakeDomain.new($workflow_type)
|
1386
|
+
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1408
1387
|
|
1409
|
-
|
1410
|
-
swf_client = FakeServiceClient.new
|
1411
|
-
domain = FakeDomain.new($workflow_type)
|
1412
|
-
client = AWS::Flow::workflow_client(swf_client, domain) { { from_class: "WorkflowOutputTooLarge" } }
|
1388
|
+
task_list = "WorkflowsOutputTooLarge"
|
1413
1389
|
|
1414
|
-
|
1390
|
+
client.start_execution
|
1391
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, WorkflowOutputTooLarge)
|
1392
|
+
worker.start
|
1393
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1394
|
+
end
|
1415
1395
|
|
1416
|
-
client.start_execution
|
1417
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, WorkflowOutputTooLarge)
|
1418
|
-
worker.start
|
1419
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1420
|
-
end
|
1421
1396
|
|
1397
|
+
it "ensures that child workflows returning exceptions > 32k get wrapped correctly" do
|
1422
1398
|
|
1423
|
-
|
1399
|
+
class ChildWorkflowOutputTooLargeTestWorkflow
|
1400
|
+
extend Workflows
|
1401
|
+
workflow(:entry_point, :child) do
|
1402
|
+
{
|
1403
|
+
version: "1.0",
|
1404
|
+
default_execution_start_to_close_timeout: 600,
|
1405
|
+
}
|
1406
|
+
end
|
1424
1407
|
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1408
|
+
def entry_point
|
1409
|
+
$my_workflow_client.child { { workflow_id: "child_workflow_test" }}
|
1410
|
+
end
|
1411
|
+
def child; end
|
1412
|
+
end
|
1413
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1414
|
+
def get_decision_task
|
1415
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "ChildWorkflowOutputTooLargeTestWorkflow.entry_point", "1.0")
|
1416
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1417
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1418
|
+
"DecisionTaskScheduled",
|
1419
|
+
"DecisionTaskStarted",
|
1420
|
+
"DecisionTaskCompleted",
|
1421
|
+
["StartChildWorkflowExecutionInitiated", {:workflow_id => "child_workflow_test"}],
|
1422
|
+
["ChildWorkflowExecutionStarted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1423
|
+
"DecisionTaskScheduled",
|
1424
|
+
"DecisionTaskStarted",
|
1425
|
+
["ChildWorkflowExecutionFailed", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test", :workflow_type => fake_workflow_type, :reason => "a"*245+"[TRUNCATED]", :details => "SIMULATED"}],
|
1426
|
+
"DecisionTaskScheduled",
|
1427
|
+
"DecisionTaskStarted",
|
1428
|
+
]))
|
1429
|
+
end
|
1432
1430
|
end
|
1431
|
+
workflow_type = FakeWorkflowType.new(nil, "ChildWorkflowOutputTooLargeTestWorkflow.entry_point", "1")
|
1433
1432
|
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
def child; end
|
1438
|
-
end
|
1439
|
-
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1440
|
-
def get_decision_task
|
1441
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "ChildWorkflowOutputTooLargeTestWorkflow.entry_point", "1.0")
|
1442
|
-
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1443
|
-
FakeEvents.new(["WorkflowExecutionStarted",
|
1444
|
-
"DecisionTaskScheduled",
|
1445
|
-
"DecisionTaskStarted",
|
1446
|
-
"DecisionTaskCompleted",
|
1447
|
-
["StartChildWorkflowExecutionInitiated", {:workflow_id => "child_workflow_test"}],
|
1448
|
-
["ChildWorkflowExecutionStarted", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test"}],
|
1449
|
-
"DecisionTaskScheduled",
|
1450
|
-
"DecisionTaskStarted",
|
1451
|
-
["ChildWorkflowExecutionFailed", {:workflow_execution => FakeWorkflowExecution.new("1", "child_workflow_test"), :workflow_id => "child_workflow_test", :workflow_type => fake_workflow_type, :reason => "a"*245+"[TRUNCATED]", :details => "SIMULATED"}],
|
1452
|
-
"DecisionTaskScheduled",
|
1453
|
-
"DecisionTaskStarted",
|
1454
|
-
]))
|
1455
|
-
end
|
1456
|
-
end
|
1457
|
-
workflow_type = FakeWorkflowType.new(nil, "ChildWorkflowOutputTooLargeTestWorkflow.entry_point", "1")
|
1458
|
-
|
1459
|
-
domain = FakeDomain.new(workflow_type)
|
1460
|
-
swf_client = FakeServiceClient.new
|
1461
|
-
$my_workflow_client = workflow_client(swf_client, domain) { { from_class: "ChildWorkflowOutputTooLargeTestWorkflow" } }
|
1462
|
-
|
1463
|
-
task_list = "ChildWorkflowOutputTooLargeTestWorkflow"
|
1464
|
-
|
1465
|
-
$my_workflow_client.start_execution
|
1466
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, ChildWorkflowOutputTooLargeTestWorkflow)
|
1467
|
-
worker.start
|
1468
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1469
|
-
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1470
|
-
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1471
|
-
reason.should include("TRUNCATED")
|
1472
|
-
exception = FlowConstants.default_data_converter.load(details)
|
1473
|
-
exception.class.should == AWS::Flow::ChildWorkflowFailedException
|
1474
|
-
exception.reason.should == "a"*245+"[TRUNCATED]"
|
1475
|
-
exception.details.should == "SIMULATED"
|
1476
|
-
end
|
1433
|
+
domain = FakeDomain.new(workflow_type)
|
1434
|
+
swf_client = FakeServiceClient.new
|
1435
|
+
$my_workflow_client = workflow_client(swf_client, domain) { { from_class: "ChildWorkflowOutputTooLargeTestWorkflow" } }
|
1477
1436
|
|
1478
|
-
|
1437
|
+
task_list = "ChildWorkflowOutputTooLargeTestWorkflow"
|
1479
1438
|
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1439
|
+
$my_workflow_client.start_execution
|
1440
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, ChildWorkflowOutputTooLargeTestWorkflow)
|
1441
|
+
worker.start
|
1442
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1443
|
+
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1444
|
+
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1445
|
+
reason.should include("TRUNCATED")
|
1446
|
+
exception = FlowConstants.data_converter.load(details)
|
1447
|
+
exception.class.should == AWS::Flow::ChildWorkflowFailedException
|
1448
|
+
exception.reason.should == "a"*245+"[TRUNCATED]"
|
1449
|
+
exception.details.should == "SIMULATED"
|
1488
1450
|
end
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1451
|
+
|
1452
|
+
it "ensures that activities returning exceptions > 32k get wrapped correctly" do
|
1453
|
+
|
1454
|
+
class ActivityExceptionTooLargeActivity
|
1455
|
+
extend Activities
|
1456
|
+
activity(:activity_a) do
|
1457
|
+
{
|
1458
|
+
version: "1.0"
|
1459
|
+
}
|
1460
|
+
end
|
1461
|
+
def activity_a; end
|
1496
1462
|
end
|
1463
|
+
class ActivityExceptionTooLargeTestWorkflow
|
1464
|
+
extend Workflows
|
1465
|
+
workflow(:entry_point) do
|
1466
|
+
{
|
1467
|
+
version: "1.0",
|
1468
|
+
default_execution_start_to_close_timeout: 600,
|
1469
|
+
}
|
1470
|
+
end
|
1497
1471
|
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1472
|
+
activity_client(:client) { { from_class: "ActivityExceptionTooLargeActivity" } }
|
1473
|
+
def entry_point
|
1474
|
+
client.activity_a
|
1475
|
+
end
|
1501
1476
|
end
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1477
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1478
|
+
def get_decision_task
|
1479
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "ActivityExceptionTooLargeTestWorkflow.entry_point", "1.0")
|
1480
|
+
TestHistoryWrapper.new(fake_workflow_type, FakeWorkflowExecution.new(nil, nil),
|
1481
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1482
|
+
"DecisionTaskScheduled",
|
1483
|
+
"DecisionTaskStarted",
|
1484
|
+
"DecisionTaskCompleted",
|
1485
|
+
["ActivityTaskScheduled", {:activity_id => "Activity1"}],
|
1486
|
+
"ActivityTaskStarted",
|
1487
|
+
["ActivityTaskFailed", scheduled_event_id: 5, activity_id: "Activity1", reason: "a"*245+"[TRUNCATED]", details: "SIMULATED"],
|
1488
|
+
"DecisionTaskScheduled",
|
1489
|
+
"DecisionTaskStarted",
|
1490
|
+
]))
|
1491
|
+
end
|
1517
1492
|
end
|
1493
|
+
workflow_type = FakeWorkflowType.new(nil, "ActivityExceptionTooLargeTestWorkflow.entry_point", "1")
|
1494
|
+
|
1495
|
+
domain = FakeDomain.new(workflow_type)
|
1496
|
+
swf_client = FakeServiceClient.new
|
1497
|
+
$my_workflow_client = workflow_client(swf_client, domain) { { from_class: "ActivityExceptionTooLargeTestWorkflow" } }
|
1498
|
+
|
1499
|
+
task_list = "ActivityExceptionTooLargeTestWorkflow"
|
1500
|
+
|
1501
|
+
$my_workflow_client.start_execution
|
1502
|
+
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, ActivityExceptionTooLargeTestWorkflow)
|
1503
|
+
worker.start
|
1504
|
+
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1505
|
+
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1506
|
+
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1507
|
+
reason.should include("TRUNCATED")
|
1508
|
+
exception = FlowConstants.data_converter.load(details)
|
1509
|
+
exception.class.should == AWS::Flow::ActivityTaskFailedException
|
1510
|
+
exception.reason.should == "a"*245+"[TRUNCATED]"
|
1511
|
+
exception.details.should == "SIMULATED"
|
1518
1512
|
end
|
1519
|
-
workflow_type = FakeWorkflowType.new(nil, "ActivityExceptionTooLargeTestWorkflow.entry_point", "1")
|
1520
|
-
|
1521
|
-
domain = FakeDomain.new(workflow_type)
|
1522
|
-
swf_client = FakeServiceClient.new
|
1523
|
-
$my_workflow_client = workflow_client(swf_client, domain) { { from_class: "ActivityExceptionTooLargeTestWorkflow" } }
|
1524
|
-
|
1525
|
-
task_list = "ActivityExceptionTooLargeTestWorkflow"
|
1526
|
-
|
1527
|
-
$my_workflow_client.start_execution
|
1528
|
-
worker = SynchronousWorkflowWorker.new(swf_client, domain, task_list, ActivityExceptionTooLargeTestWorkflow)
|
1529
|
-
worker.start
|
1530
|
-
swf_client.trace.first[:decisions].first[:decision_type].should == "FailWorkflowExecution"
|
1531
|
-
reason = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:reason]
|
1532
|
-
details = swf_client.trace.first[:decisions].first[:fail_workflow_execution_decision_attributes][:details]
|
1533
|
-
reason.should include("TRUNCATED")
|
1534
|
-
exception = FlowConstants.default_data_converter.load(details)
|
1535
|
-
exception.class.should == AWS::Flow::ActivityTaskFailedException
|
1536
|
-
exception.reason.should == "a"*245+"[TRUNCATED]"
|
1537
|
-
exception.details.should == "SIMULATED"
|
1538
|
-
end
|
1539
1513
|
|
1540
1514
|
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1515
|
+
# A bug was introduced in the previous commit which resulted in unnecessary
|
1516
|
+
# calls to #describe_workflow_execution during logging of a DecisionTask. This
|
1517
|
+
# test ensures that we don't call describe_workflow_execution anymore.
|
1518
|
+
it "ensures describe_workflow_execution is not called during polling" do
|
1545
1519
|
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1520
|
+
swf = double("swf")
|
1521
|
+
domain = double("domain")
|
1522
|
+
allow(domain).to receive(:name).and_return("foo")
|
1523
|
+
allow(swf).to receive(:domain).and_return(domain)
|
1550
1524
|
|
1551
|
-
|
1552
|
-
|
1525
|
+
# Set the expectations for the test
|
1526
|
+
expect_any_instance_of(AWS::SimpleWorkflow::Client::V20120125).to_not receive(:describe_workflow_execution)
|
1553
1527
|
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1528
|
+
class SomeWorkflow
|
1529
|
+
extend Workflows
|
1530
|
+
workflow(:start) do
|
1531
|
+
{
|
1532
|
+
version: "1.0",
|
1533
|
+
default_execution_start_to_close_timeout: 600,
|
1534
|
+
}
|
1535
|
+
end
|
1536
|
+
def start; end
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
|
1540
|
+
def get_decision_task
|
1541
|
+
fake_workflow_type = FakeWorkflowType.new(nil, "SomeWorkflow.start", "1.0")
|
1542
|
+
domain = double("domain")
|
1543
|
+
TestHistoryWrapper.new(fake_workflow_type, AWS::SimpleWorkflow::WorkflowExecution.new(domain, "workflow_id", "run_id"),
|
1544
|
+
FakeEvents.new(["WorkflowExecutionStarted",
|
1545
|
+
"DecisionTaskScheduled",
|
1546
|
+
"DecisionTaskStarted",
|
1547
|
+
]))
|
1548
|
+
end
|
1561
1549
|
end
|
1562
|
-
|
1563
|
-
|
1550
|
+
workflow_type = FakeWorkflowType.new(nil, "SomeWorkflow.entry_point", "1")
|
1551
|
+
client = workflow_client(swf, domain) { { from_class: "SomeWorkflow" } }
|
1564
1552
|
|
1565
|
-
|
1566
|
-
|
1567
|
-
fake_workflow_type = FakeWorkflowType.new(nil, "SomeWorkflow.start", "1.0")
|
1568
|
-
domain = double("domain")
|
1569
|
-
TestHistoryWrapper.new(fake_workflow_type, AWS::SimpleWorkflow::WorkflowExecution.new(domain, "workflow_id", "run_id"),
|
1570
|
-
FakeEvents.new(["WorkflowExecutionStarted",
|
1571
|
-
"DecisionTaskScheduled",
|
1572
|
-
"DecisionTaskStarted",
|
1573
|
-
]))
|
1574
|
-
end
|
1553
|
+
worker = SynchronousWorkflowWorker.new(swf, domain, "SomeWorkflow", SomeWorkflow)
|
1554
|
+
worker.start
|
1575
1555
|
end
|
1576
|
-
workflow_type = FakeWorkflowType.new(nil, "SomeWorkflow.entry_point", "1")
|
1577
|
-
client = workflow_client(swf, domain) { { from_class: "SomeWorkflow" } }
|
1578
1556
|
|
1579
|
-
worker = SynchronousWorkflowWorker.new(swf, domain, "SomeWorkflow", SomeWorkflow)
|
1580
|
-
worker.start
|
1581
1557
|
end
|
1582
|
-
|
1583
1558
|
end
|
1584
|
-
|