aws-flow 1.0.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.
- data/Gemfile +8 -0
- data/LICENSE.TXT +15 -0
- data/NOTICE.TXT +14 -0
- data/Rakefile +39 -0
- data/aws-flow-core/Gemfile +9 -0
- data/aws-flow-core/LICENSE.TXT +15 -0
- data/aws-flow-core/NOTICE.TXT +14 -0
- data/aws-flow-core/Rakefile +27 -0
- data/aws-flow-core/aws-flow-core.gemspec +12 -0
- data/aws-flow-core/lib/aws/flow.rb +26 -0
- data/aws-flow-core/lib/aws/flow/async_backtrace.rb +134 -0
- data/aws-flow-core/lib/aws/flow/async_scope.rb +195 -0
- data/aws-flow-core/lib/aws/flow/begin_rescue_ensure.rb +386 -0
- data/aws-flow-core/lib/aws/flow/fiber.rb +77 -0
- data/aws-flow-core/lib/aws/flow/flow_utils.rb +50 -0
- data/aws-flow-core/lib/aws/flow/future.rb +109 -0
- data/aws-flow-core/lib/aws/flow/implementation.rb +151 -0
- data/aws-flow-core/lib/aws/flow/simple_dfa.rb +85 -0
- data/aws-flow-core/lib/aws/flow/tasks.rb +405 -0
- data/aws-flow-core/test/aws/async_backtrace_spec.rb +41 -0
- data/aws-flow-core/test/aws/async_scope_spec.rb +118 -0
- data/aws-flow-core/test/aws/begin_rescue_ensure_spec.rb +665 -0
- data/aws-flow-core/test/aws/external_task_spec.rb +197 -0
- data/aws-flow-core/test/aws/factories.rb +52 -0
- data/aws-flow-core/test/aws/fiber_condition_variable_spec.rb +163 -0
- data/aws-flow-core/test/aws/fiber_spec.rb +78 -0
- data/aws-flow-core/test/aws/flow_spec.rb +255 -0
- data/aws-flow-core/test/aws/future_spec.rb +210 -0
- data/aws-flow-core/test/aws/rubyflow.rb +22 -0
- data/aws-flow-core/test/aws/simple_dfa_spec.rb +63 -0
- data/aws-flow-core/test/aws/spec_helper.rb +36 -0
- data/aws-flow.gemspec +13 -0
- data/lib/aws/decider.rb +67 -0
- data/lib/aws/decider/activity.rb +408 -0
- data/lib/aws/decider/activity_definition.rb +111 -0
- data/lib/aws/decider/async_decider.rb +673 -0
- data/lib/aws/decider/async_retrying_executor.rb +153 -0
- data/lib/aws/decider/data_converter.rb +40 -0
- data/lib/aws/decider/decider.rb +511 -0
- data/lib/aws/decider/decision_context.rb +60 -0
- data/lib/aws/decider/exceptions.rb +178 -0
- data/lib/aws/decider/executor.rb +149 -0
- data/lib/aws/decider/flow_defaults.rb +70 -0
- data/lib/aws/decider/generic_client.rb +178 -0
- data/lib/aws/decider/history_helper.rb +173 -0
- data/lib/aws/decider/implementation.rb +82 -0
- data/lib/aws/decider/options.rb +607 -0
- data/lib/aws/decider/state_machines.rb +373 -0
- data/lib/aws/decider/task_handler.rb +76 -0
- data/lib/aws/decider/task_poller.rb +207 -0
- data/lib/aws/decider/utilities.rb +187 -0
- data/lib/aws/decider/worker.rb +324 -0
- data/lib/aws/decider/workflow_client.rb +374 -0
- data/lib/aws/decider/workflow_clock.rb +104 -0
- data/lib/aws/decider/workflow_definition.rb +101 -0
- data/lib/aws/decider/workflow_definition_factory.rb +53 -0
- data/lib/aws/decider/workflow_enabled.rb +26 -0
- data/test/aws/decider_spec.rb +1299 -0
- data/test/aws/factories.rb +45 -0
- data/test/aws/integration_spec.rb +3108 -0
- data/test/aws/spec_helper.rb +23 -0
- metadata +138 -0
@@ -0,0 +1,374 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
5
|
+
# You may not use this file except in compliance with the License.
|
6
|
+
# A copy of the License is located at
|
7
|
+
#
|
8
|
+
# http://aws.amazon.com/apache2.0
|
9
|
+
#
|
10
|
+
# or in the "license" file accompanying this file. This file is distributed
|
11
|
+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
12
|
+
# express or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
#++
|
15
|
+
|
16
|
+
module AWS
|
17
|
+
module Flow
|
18
|
+
|
19
|
+
|
20
|
+
# A future provided by a [WorkflowExecution](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/WorkflowExecution.html).
|
21
|
+
#
|
22
|
+
# @!attribute _workflow_execution
|
23
|
+
# The [WorkflowExecution](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/WorkflowExecution.html)
|
24
|
+
# instance that this future belongs to.
|
25
|
+
#
|
26
|
+
# @!attribute return_value
|
27
|
+
# The return value of the future.
|
28
|
+
#
|
29
|
+
class WorkflowFuture
|
30
|
+
attr_accessor :_workflow_execution, :return_value
|
31
|
+
|
32
|
+
|
33
|
+
# Creates a new workflow future
|
34
|
+
#
|
35
|
+
# @param workflow_execution
|
36
|
+
#
|
37
|
+
def initialize(workflow_execution)
|
38
|
+
@_workflow_execution = workflow_execution
|
39
|
+
@return_value = Future.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(method_name, *args, &block)
|
43
|
+
@return_value.send(method_name, *args, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Gets the current value of the workflow execution
|
48
|
+
# @return
|
49
|
+
def workflow_execution
|
50
|
+
@_workflow_execution
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
# @!visibility private
|
58
|
+
class NoInput
|
59
|
+
def empty?; return true; end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# A client for a workflow execution.
|
64
|
+
#
|
65
|
+
# @!attribute domain
|
66
|
+
# The SWF domain used for this workflow.
|
67
|
+
#
|
68
|
+
# @!attribute [Hash, WorkflowOptions] options
|
69
|
+
# Workflow options for this client.
|
70
|
+
#
|
71
|
+
class WorkflowClient < GenericClient
|
72
|
+
attr_accessor :domain, :options
|
73
|
+
|
74
|
+
# Creates a new {WorkflowClient}
|
75
|
+
#
|
76
|
+
# @param service
|
77
|
+
# The SWF [Client](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/Client.html) to use for
|
78
|
+
# creating this {WorkflowClient}.
|
79
|
+
#
|
80
|
+
# @param domain
|
81
|
+
# The SWF [Domain](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/Domain.html) in which to
|
82
|
+
# start the workflow execution.
|
83
|
+
#
|
84
|
+
# @param workflow_class
|
85
|
+
#
|
86
|
+
# @param [Hash, WorkflowOptions] options
|
87
|
+
# Workflow options for this client.
|
88
|
+
#
|
89
|
+
def initialize(service, domain, workflow_class, options)
|
90
|
+
@service = service
|
91
|
+
@domain = domain
|
92
|
+
@workflow_class = workflow_class
|
93
|
+
@options = options
|
94
|
+
@failure_map = {}
|
95
|
+
super
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# @!visibility private
|
100
|
+
def self.default_option_class; WorkflowOptions; end
|
101
|
+
|
102
|
+
# Gets the events for this workflow client
|
103
|
+
#
|
104
|
+
def events
|
105
|
+
@execution.events if @execution
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
# Gets the current {DecisionContext} for the workflow client.
|
110
|
+
#
|
111
|
+
def get_decision_context
|
112
|
+
@decision_context ||= FlowFiber.current[:decision_context]
|
113
|
+
@decision_helper ||= @decision_context.decision_helper
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Begins executing this workflow.
|
118
|
+
#
|
119
|
+
# @param input
|
120
|
+
# Input to provide to the
|
121
|
+
#
|
122
|
+
# @param [Hash, StartWorkflowOptions] block
|
123
|
+
# A hash of {StartWorkflowOptions} to use for this workflow execution.
|
124
|
+
#
|
125
|
+
def start_execution(*input, &block)
|
126
|
+
if Utilities::is_external
|
127
|
+
self.start_external_workflow(input, &block)
|
128
|
+
else
|
129
|
+
self.start_internal_workflow(input, &block)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Records a `WorkflowExecutionSignaled` event in the workflow execution history and creates a decision task for
|
134
|
+
# the workflow execution. The event is recorded with the specified user-defined signal name and input (if
|
135
|
+
# provided).
|
136
|
+
#
|
137
|
+
# @param signal_name
|
138
|
+
# The user-defined name of the signal.
|
139
|
+
#
|
140
|
+
# @param workflow_execution
|
141
|
+
# The workflow execution to signal.
|
142
|
+
#
|
143
|
+
# @param [Hash, SignalWorkflowOptions] block
|
144
|
+
# A block of {SignalWorkflowOptions} for the `WorkflowExecutionSignaled` event.
|
145
|
+
#
|
146
|
+
def signal_workflow_execution(signal_name = nil, workflow_execution = nil, &block)
|
147
|
+
if Utilities::is_external
|
148
|
+
self.signal_external_workflow(signal_name, workflow_execution, &block)
|
149
|
+
else
|
150
|
+
self.signal_internal_workflow(signal_name, workflow_execution, &block)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
# Called by {#signal_workflow_execution}
|
156
|
+
# @!visibility private
|
157
|
+
def signal_external_workflow(signal_name, workflow_execution, &block)
|
158
|
+
options = Utilities::interpret_block_for_options(SignalWorkflowOptions, block)
|
159
|
+
options.signal_name ||= signal_name
|
160
|
+
if workflow_execution
|
161
|
+
options.domain ||= workflow_execution.domain.name.to_s
|
162
|
+
options.workflow_id ||= workflow_execution.workflow_id.to_s
|
163
|
+
end
|
164
|
+
@service.signal_workflow_execution(options.get_full_options)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Called by {#signal_workflow_execution}
|
168
|
+
# @!visibility private
|
169
|
+
def signal_internal_workflow(signal_name, workflow_execution, &block)
|
170
|
+
get_decision_context
|
171
|
+
options = Utilities::interpret_block_for_options(SignalWorkflowOptions, block)
|
172
|
+
# Unpack the workflow execution from the future
|
173
|
+
workflow_execution = workflow_execution.workflow_execution if workflow_execution.respond_to? :workflow_execution
|
174
|
+
options.signal_name ||= signal_name.to_s
|
175
|
+
options.workflow_id ||= workflow_execution.workflow_id.get.to_s
|
176
|
+
execution_method = options.execution_method || @options.execution_method
|
177
|
+
raise "You haven't specified an execution method!" if execution_method.nil?
|
178
|
+
Utilities::merge_all_options(options)
|
179
|
+
open_request = OpenRequestInfo.new
|
180
|
+
decision_id = @decision_helper.get_next_id(:Signal)
|
181
|
+
options.control ||= decision_id
|
182
|
+
external_task do |external|
|
183
|
+
external.initiate_task do |handle|
|
184
|
+
@decision_helper[decision_id] = SignalDecisionStateMachine.new(decision_id, options)
|
185
|
+
open_request.completion_handle = handle
|
186
|
+
@decision_helper.scheduled_signals[decision_id] = open_request
|
187
|
+
end
|
188
|
+
external.cancellation_handler do |handle, cause|
|
189
|
+
@decision_helper[decision_id].consume(:cancel)
|
190
|
+
open_request = @decision_helper.scheduled_signal.delete(decision_id)
|
191
|
+
raise "Signal #{decision_id} wasn't scheduled" unless open_request
|
192
|
+
handle.complete
|
193
|
+
end
|
194
|
+
end
|
195
|
+
return open_request.result
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Called by {#start_execution}
|
200
|
+
# @!visibility private
|
201
|
+
def start_internal_workflow(input = NoInput.new, &block)
|
202
|
+
get_decision_context
|
203
|
+
options = Utilities::interpret_block_for_options(StartWorkflowOptions, block)
|
204
|
+
workflow_id_future, run_id_future = Future.new, Future.new
|
205
|
+
output = WorkflowFuture.new(AWS::SimpleWorkflow::WorkflowExecution.new(@domain, workflow_id_future, run_id_future))
|
206
|
+
options = Utilities::merge_all_options(@options, options)
|
207
|
+
new_options = StartWorkflowOptions.new(options)
|
208
|
+
open_request = OpenRequestInfo.new
|
209
|
+
workflow_id = new_options.workflow_id
|
210
|
+
run_id = @decision_context.workflow_context.decision_task.workflow_execution.run_id
|
211
|
+
workflow_id ||= @decision_helper.get_next_id(run_id.to_s + ":")
|
212
|
+
workflow_id_future.set(workflow_id)
|
213
|
+
error_handler do |t|
|
214
|
+
t.begin do
|
215
|
+
@data_converter = new_options.data_converter
|
216
|
+
input = @data_converter.dump input unless input.empty?
|
217
|
+
attributes = {}
|
218
|
+
new_options.input ||= input unless input.empty?
|
219
|
+
if @workflow_class != nil && new_options.execution_method.nil?
|
220
|
+
new_options.execution_method = @workflow_class.entry_point
|
221
|
+
end
|
222
|
+
raise "Can't find an execution method for workflow #{@workflow_class}" if new_options.execution_method.nil?
|
223
|
+
|
224
|
+
attributes[:options] = new_options
|
225
|
+
attributes[:workflow_id] = workflow_id
|
226
|
+
# TODO Use ChildWorkflowOptions
|
227
|
+
attributes[:tag_list] = []
|
228
|
+
|
229
|
+
external_task do |external|
|
230
|
+
external.initiate_task do |handle|
|
231
|
+
open_request.completion_handle = handle
|
232
|
+
open_request.run_id = run_id_future
|
233
|
+
open_request.description = output.workflow_execution
|
234
|
+
@decision_helper.scheduled_external_workflows[workflow_id.to_s] = open_request
|
235
|
+
@decision_helper[workflow_id.to_s] = ChildWorkflowDecisionStateMachine.new(workflow_id, attributes)
|
236
|
+
end
|
237
|
+
|
238
|
+
external.cancellation_handler do |handle, cause|
|
239
|
+
state_machine = @decision_helper[workflow_id.to_s]
|
240
|
+
if state_machine.current_state == :created
|
241
|
+
open_request = @decision_helper.scheduled_external_workflows.delete(workflow_id)
|
242
|
+
open_request.complete
|
243
|
+
end
|
244
|
+
state_machine.consume(:cancel)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
t.rescue(Exception) do |error|
|
249
|
+
if error.is_a? ChildWorkflowFailedException
|
250
|
+
details = @data_converter.load(error.details)
|
251
|
+
error.details = details
|
252
|
+
error.cause = details
|
253
|
+
end
|
254
|
+
@failure_map[workflow_id.to_s] = error
|
255
|
+
end
|
256
|
+
t.ensure do
|
257
|
+
result = @data_converter.load open_request.result
|
258
|
+
output.set(result)
|
259
|
+
raise @failure_map[workflow_id.to_s] if @failure_map[workflow_id.to_s] && new_options.return_on_start
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
return output if new_options.return_on_start
|
264
|
+
output.get
|
265
|
+
this_failure = @failure_map[workflow_id.to_s]
|
266
|
+
raise this_failure if this_failure
|
267
|
+
return output.get
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
# Called by {#start_execution}
|
272
|
+
# @!visibility private
|
273
|
+
def start_external_workflow(input = NoInput.new, &block)
|
274
|
+
options = Utilities::interpret_block_for_options(StartWorkflowOptions, block)
|
275
|
+
options = Utilities::merge_all_options(@options, options)
|
276
|
+
@converter ||= YAMLDataConverter.new
|
277
|
+
# Basically, we want to avoid the special "NoInput, but allow stuff like nil in"
|
278
|
+
if ! (input.class <= NoInput || input.empty?)
|
279
|
+
options[:input] = @converter.dump input
|
280
|
+
end
|
281
|
+
if @workflow_class.nil?
|
282
|
+
execution_method = @options.execution_method
|
283
|
+
version = @options.version
|
284
|
+
else
|
285
|
+
# TODO This is a nasty hack
|
286
|
+
workflow_type = @workflow_class.workflows.first
|
287
|
+
execution_method = workflow_type.options.execution_method
|
288
|
+
version = workflow_type.version
|
289
|
+
end
|
290
|
+
version = options[:version] ? options[:version] : version
|
291
|
+
execution_method = options[:execution_method] ? options[:execution_method] : execution_method
|
292
|
+
raise "Can't find an execution method for workflow #{workflow_class}" if execution_method.nil?
|
293
|
+
# TODO A real workflowtype function
|
294
|
+
workflow_name = @options.workflow_name || @options.prefix_name
|
295
|
+
workflow_type_name = workflow_name.to_s + "." + execution_method.to_s
|
296
|
+
|
297
|
+
task_list = options[:task_list]
|
298
|
+
options[:task_list] = { :name => task_list } if options[:task_list]
|
299
|
+
options[:workflow_id] ||= UUIDTools::UUID.random_create.to_s
|
300
|
+
options[:domain] = @domain.name
|
301
|
+
options[:workflow_type] = {
|
302
|
+
:name => workflow_type_name.to_s,
|
303
|
+
:version => version.to_s
|
304
|
+
}
|
305
|
+
[:prefix_name, :workflow_name, :version, :execution_method, :data_converter].each {|key| options.delete(key)}
|
306
|
+
run_id = @service.start_workflow_execution(options)["runId"]
|
307
|
+
this_workflow = @domain.workflow_executions.at(options[:workflow_id], run_id)
|
308
|
+
this_workflow
|
309
|
+
end
|
310
|
+
|
311
|
+
def is_execution_method(method_name)
|
312
|
+
(@workflow_class.workflows.map(&:options).map(&:execution_method).map(&:to_sym).include? method_name) || method_name == @workflow_class.entry_point
|
313
|
+
end
|
314
|
+
|
315
|
+
def method_missing(method_name, *args, &block)
|
316
|
+
if is_execution_method(method_name)
|
317
|
+
start_execution(*args, &block)
|
318
|
+
else
|
319
|
+
super(method_name, *args, &block)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
def request_cancel_workflow_execution(future)
|
323
|
+
workflow_execution = future.workflow_execution
|
324
|
+
run_id = workflow_execution.run_id.get
|
325
|
+
workflow_id = workflow_execution.workflow_id.get
|
326
|
+
state_machine = @decision_helper[workflow_id]
|
327
|
+
state_machine.run_id = run_id
|
328
|
+
state_machine.consume(:cancel)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
# Instances of WorkflowFactory are generated by {#workflow_factory}.
|
334
|
+
class WorkflowFactory
|
335
|
+
|
336
|
+
|
337
|
+
# Creates a new WorkflowFactory with the provided parameters. The construction parameters will be used for any
|
338
|
+
# workflow clients generated by this workflow factory.
|
339
|
+
#
|
340
|
+
# @param service
|
341
|
+
# The service to use for workflow clients generated by this workflow factory
|
342
|
+
#
|
343
|
+
# @param domain
|
344
|
+
# The SWF [Domain](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/Domain.html) to use for
|
345
|
+
# workflow clients generated by this workflow factory
|
346
|
+
#
|
347
|
+
# @param block
|
348
|
+
# A block of {StartWorkflowOptions} to use for clients generated by this workflow factory.
|
349
|
+
#
|
350
|
+
def initialize(service, domain, block)
|
351
|
+
@service = service
|
352
|
+
@domain = domain
|
353
|
+
@options = Utilities::interpret_block_for_options(StartWorkflowOptions, block)
|
354
|
+
@workflow_class = get_const(@options.workflow_name) rescue nil
|
355
|
+
if @workflow_class
|
356
|
+
workflow_type = @workflow_class.workflows.delete_if {|wf_type| wf_type.version.nil? }.first
|
357
|
+
@options.version = workflow_type.version
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
|
362
|
+
# Get a {WorkflowClient} with the parameters used in the construction of this {WorkflowFactory}.
|
363
|
+
#
|
364
|
+
# @return [WorkflowClient]
|
365
|
+
# A workflow client, created with the parameters used when creating the {WorkflowFactory}.
|
366
|
+
#
|
367
|
+
def get_client
|
368
|
+
WorkflowClient.new(@service, @domain, @workflow_class, @options)
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
5
|
+
# You may not use this file except in compliance with the License.
|
6
|
+
# A copy of the License is located at
|
7
|
+
#
|
8
|
+
# http://aws.amazon.com/apache2.0
|
9
|
+
#
|
10
|
+
# or in the "license" file accompanying this file. This file is distributed
|
11
|
+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
12
|
+
# express or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
#++
|
15
|
+
|
16
|
+
module AWS
|
17
|
+
module Flow
|
18
|
+
|
19
|
+
|
20
|
+
# Represents a workflow clock that can create timers.
|
21
|
+
class WorkflowClock
|
22
|
+
|
23
|
+
# Gets or sets the replaying status of the workflow clock.
|
24
|
+
attr_accessor :replaying
|
25
|
+
|
26
|
+
# Gets or sets the current time in milliseconds for a replay.
|
27
|
+
attr_accessor :replay_current_time_millis
|
28
|
+
|
29
|
+
|
30
|
+
# Create a new {WorkflowClock} instance.
|
31
|
+
#
|
32
|
+
# @param [DecisionHelper] decision_helper
|
33
|
+
# The decision helper used by the workflow clock to schedule and execute timers.
|
34
|
+
#
|
35
|
+
def initialize(decision_helper)
|
36
|
+
#Map from timerIDs to OpenRequestInfo
|
37
|
+
@scheduled_timers = {}
|
38
|
+
@replaying = true
|
39
|
+
@replay_current_time_millis
|
40
|
+
@decision_helper = decision_helper
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Get the current time.
|
45
|
+
#
|
46
|
+
# @return [Time]
|
47
|
+
# A `Time` object initialized to the the current time in milliseconds for a replay. This is the same time that
|
48
|
+
# is provided by the `:replay_current_time_millis` attribute.
|
49
|
+
#
|
50
|
+
def current_time
|
51
|
+
@replay_current_time_millis
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create a new timer that executes the supplied block after a specified number of seconds.
|
55
|
+
#
|
56
|
+
# @param delay_seconds
|
57
|
+
# The number of seconds to wait before executing the block. Set to 0 to execute the block immediately.
|
58
|
+
#
|
59
|
+
# @param block
|
60
|
+
# A block to execute after `delay_seconds` has expired.
|
61
|
+
#
|
62
|
+
def create_timer(delay_seconds, block)
|
63
|
+
raise IllegalArgumentException if delay_seconds < 0
|
64
|
+
if delay_seconds == 0
|
65
|
+
if block
|
66
|
+
return block.call
|
67
|
+
else
|
68
|
+
return
|
69
|
+
end
|
70
|
+
end
|
71
|
+
attributes = {}
|
72
|
+
timer_id = @decision_helper.get_next_id(:Timer)
|
73
|
+
attributes[:timer_id] = timer_id
|
74
|
+
attributes[:start_to_fire_timeout] = delay_seconds.to_s
|
75
|
+
open_request = OpenRequestInfo.new
|
76
|
+
open_request.blocking_promise = Future.new
|
77
|
+
if block
|
78
|
+
open_request.result = task do
|
79
|
+
open_request.blocking_promise.get
|
80
|
+
block.call
|
81
|
+
end
|
82
|
+
else
|
83
|
+
open_request.result = open_request.blocking_promise
|
84
|
+
end
|
85
|
+
external_task do |t|
|
86
|
+
t.initiate_task do |handle|
|
87
|
+
open_request.completion_handle = handle
|
88
|
+
@decision_helper.scheduled_timers[timer_id.to_s] = open_request
|
89
|
+
@decision_helper[timer_id.to_s] = TimerDecisionStateMachine.new(timer_id, attributes)
|
90
|
+
end
|
91
|
+
t.cancellation_handler do |handle, cause|
|
92
|
+
state_machine = @decision_helper[timer_id]
|
93
|
+
open_request = @decision_helper.scheduled_timers.delete(timer_id)
|
94
|
+
open_request.completion_handle.complete
|
95
|
+
state_machine.consume(:cancel)
|
96
|
+
state_machine.cancelled = true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return open_request.result.get
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|