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,178 @@
|
|
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
|
+
# A generic activity client.
|
20
|
+
class GenericClient
|
21
|
+
|
22
|
+
# The option map for the client.
|
23
|
+
attr_accessor :option_map
|
24
|
+
|
25
|
+
# Creates a new generic client.
|
26
|
+
def initialize(*args)
|
27
|
+
@option_map = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Sets a map of options for this client.
|
32
|
+
#
|
33
|
+
# @param opts
|
34
|
+
# The options to set.
|
35
|
+
#
|
36
|
+
def with_opts(opts = {})
|
37
|
+
klass = self.class.default_option_class
|
38
|
+
options = klass.new(opts)
|
39
|
+
modified_instance = self.dup
|
40
|
+
options = klass.new(Utilities::merge_all_options(modified_instance.options, options))
|
41
|
+
modified_instance.options = options
|
42
|
+
modified_instance
|
43
|
+
end
|
44
|
+
|
45
|
+
def reconfigure(*method_names, &block)
|
46
|
+
options = Utilities::interpret_block_for_options(self.class.default_option_class, block)
|
47
|
+
method_names.each { |method_name| @option_map[method_name.to_sym] = options }
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!visibility private
|
51
|
+
def bail_if_external
|
52
|
+
raise "You cannot use this function outside of a workflow definition" if Utilities::is_external
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Starts an asynchronous execution of a task. This method returns immediately; it does not wait for the task to
|
57
|
+
# complete.
|
58
|
+
#
|
59
|
+
# @note Trying to use {#send_async} outside of a workflow will fail with an exception.
|
60
|
+
#
|
61
|
+
# @param task The task to execute.
|
62
|
+
#
|
63
|
+
# @param args A number of arguments used to start the task execution.
|
64
|
+
#
|
65
|
+
# @param block A code block with additional options to start the task execution.
|
66
|
+
#
|
67
|
+
# @example The following two calls are equivalent.
|
68
|
+
# foo.send_async :bar # plus args and block if appropriate
|
69
|
+
#
|
70
|
+
# task do
|
71
|
+
# foo.send :bar # plus args and block if appropriate
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
def send_async(task, *args, &block)
|
75
|
+
bail_if_external
|
76
|
+
# If there is no block, just make a block for immediate return
|
77
|
+
if block.nil?
|
78
|
+
modified_options = Proc.new{ {:return_on_start => true } }
|
79
|
+
# If there is a block, and it doesn't take any arguments, it will evaluate to a hash. Add an option to the hash
|
80
|
+
elsif block.arity == 0
|
81
|
+
modified_options = Proc.new do
|
82
|
+
result = block.call
|
83
|
+
result[:return_on_start] = true
|
84
|
+
result
|
85
|
+
end
|
86
|
+
# Otherwise, it will expect an options object passed in, and will do things on that object. So make our new Proc do that, and add an option
|
87
|
+
else modified_options = Proc.new do |x|
|
88
|
+
result = block.call(x)
|
89
|
+
result.return_on_start = true
|
90
|
+
result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
self.send(task, *args, &modified_options)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Retries the given method using an exponential fallback function.
|
98
|
+
def exponential_retry(method_name, *args, &block)
|
99
|
+
future = self._retry(method_name, FlowConstants.exponential_retry_function, block, args)
|
100
|
+
Utilities::drill_on_future(future)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
# Used by {#retry}
|
106
|
+
# @!visibility private
|
107
|
+
def _retry_with_options(lambda_to_execute, retry_function, retry_options, args = NoInput.new)
|
108
|
+
retry_policy = RetryPolicy.new(retry_function, retry_options)
|
109
|
+
output = Utilities::AddressableFuture.new
|
110
|
+
result = nil
|
111
|
+
failure = nil
|
112
|
+
error_handler do |t|
|
113
|
+
t.begin do
|
114
|
+
async_retrying_executor = AsyncRetryingExecutor.new(retry_policy, self.decision_context.workflow_clock, self.decision_context.workflow_context.decision_task.workflow_execution.run_id, retry_options.return_on_start)
|
115
|
+
result = async_retrying_executor.execute(lambda_to_execute)
|
116
|
+
end
|
117
|
+
t.rescue(Exception) do |error|
|
118
|
+
failure = error
|
119
|
+
end
|
120
|
+
t.ensure do
|
121
|
+
if failure.nil?
|
122
|
+
output.set(result)
|
123
|
+
else
|
124
|
+
output.set(nil)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
return output if retry_options.return_on_start
|
129
|
+
output.get
|
130
|
+
raise failure unless failure.nil?
|
131
|
+
return output.get
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Retries the given method using an optional retry function and block of {RetryOptions}.
|
136
|
+
#
|
137
|
+
# @param (see #retry)
|
138
|
+
#
|
139
|
+
# @!visibility private
|
140
|
+
def _retry(method_name, retry_function, block, args = NoInput.new)
|
141
|
+
bail_if_external
|
142
|
+
retry_options = Utilities::interpret_block_for_options(RetryOptions, block)
|
143
|
+
_retry_with_options(lambda { self.send(method_name, *args) }, retry_function, retry_options)
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# Retries the given method using an optional retry function and block of {RetryOptions}.
|
148
|
+
#
|
149
|
+
# @param method_name
|
150
|
+
# The activity to retry.
|
151
|
+
#
|
152
|
+
# @param retry_function
|
153
|
+
# The retry function to use
|
154
|
+
#
|
155
|
+
# @param args
|
156
|
+
# Arguments to send to the method named in the `method_name` parameter.
|
157
|
+
#
|
158
|
+
# @param block
|
159
|
+
# The {RetryOptions} to set.
|
160
|
+
#
|
161
|
+
def retry(method_name, retry_function, *args, &block)
|
162
|
+
if retry_function.is_a? Fixnum
|
163
|
+
retry_time = retry_function
|
164
|
+
retry_function = lambda {|first_attempt, time_of_failure, attempt| retry_time}
|
165
|
+
end
|
166
|
+
future = self._retry(method_name, retry_function, block, args)
|
167
|
+
Utilities::drill_on_future(future)
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# @return The decision context for this client.
|
172
|
+
def decision_context
|
173
|
+
FlowFiber.current[:decision_context]
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
5
|
+
# You may not use this file except in compliance with the License.
|
6
|
+
# A copy of the License is located at
|
7
|
+
#
|
8
|
+
# http://aws.amazon.com/apache2.0
|
9
|
+
#
|
10
|
+
# or in the "license" file accompanying this file. This file is distributed
|
11
|
+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
12
|
+
# express or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
#++
|
15
|
+
|
16
|
+
require 'set'
|
17
|
+
|
18
|
+
module AWS
|
19
|
+
module Flow
|
20
|
+
class HistoryHelper
|
21
|
+
def initialize(decision_task_iterator)
|
22
|
+
# TODO make sure we page through correctly
|
23
|
+
@single_decision_events_iterator = SingleDecisionIterator.new(decision_task_iterator)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_single_decision_events
|
27
|
+
@current_decision_data = @single_decision_events_iterator.next
|
28
|
+
return @current_decision_data.decision_events
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_replay_current_time_millis
|
32
|
+
raise IllegalStateException if @current_decision_data.nil?
|
33
|
+
@current_decision_data.replay_current_time_milliseconds
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_last_non_replay_event_id
|
37
|
+
result = get_decision_task.previous_started_event_id
|
38
|
+
result ||= 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_decision_task
|
42
|
+
@single_decision_events_iterator.get_decision_task
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class EventsIterator
|
47
|
+
attr_accessor :events, :decision_task, :decision_tasks
|
48
|
+
|
49
|
+
def initialize(decision_tasks)
|
50
|
+
@decision_tasks = decision_tasks
|
51
|
+
if ! @decision_tasks.nil?
|
52
|
+
@decision_task = decision_tasks
|
53
|
+
@events = @decision_task.events.to_a
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class SingleDecisionData
|
59
|
+
attr_reader :decision_events, :replay_current_time_milliseconds, :workflow_context_data
|
60
|
+
def initialize(decision_events, replay_current_time_milliseconds, workflow_context_data)
|
61
|
+
@decision_events = decision_events
|
62
|
+
@replay_current_time_milliseconds = replay_current_time_milliseconds
|
63
|
+
@workflow_context_data = workflow_context_data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class SingleDecisionIterator
|
68
|
+
class << self
|
69
|
+
attr_accessor :decision_events
|
70
|
+
end
|
71
|
+
@decision_events = Set.new([
|
72
|
+
:ActivityTaskCancelRequested,
|
73
|
+
:ActivityTaskScheduled,
|
74
|
+
:CancelTimerFailed,
|
75
|
+
:CancelWorkflowExecutionFailed,
|
76
|
+
:CompleteWorkflowExecutionFailed,
|
77
|
+
:ContinueAsNewWorkflowExecutionFailed,
|
78
|
+
:FailWorkflowExecutionFailed,
|
79
|
+
:MarkerRecorded,
|
80
|
+
:RequestCancelActivityTaskFailed,
|
81
|
+
:RequestCancelExternalWorkflowExecutionFailed,
|
82
|
+
:RequestCancelExternalWorkflowExecutionInitiated,
|
83
|
+
:ScheduleActivityTaskFailed,
|
84
|
+
:SignalExternalWorkflowExecutionFailed,
|
85
|
+
:SignalExternalWorkflowExecutionInitiated,
|
86
|
+
:StartChildWorkflowExecutionFailed,
|
87
|
+
:StartChildWorkflowExecutionInitiated,
|
88
|
+
:StartTimerFailed,
|
89
|
+
:TimerCanceled,
|
90
|
+
:TimerStarted,
|
91
|
+
:WorkflowExecutionCanceled,
|
92
|
+
:WorkflowExecutionCompleted,
|
93
|
+
:WorkflowExecutionContinuedAsNew,
|
94
|
+
:WorkflowExecutionFailed
|
95
|
+
])
|
96
|
+
|
97
|
+
def is_decision_event?(event)
|
98
|
+
SingleDecisionIterator.decision_events.member? event
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_decision_task
|
102
|
+
@events.decision_task
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize(decision_tasks)
|
106
|
+
@events = EventsIterator.new(decision_tasks)
|
107
|
+
fill_next
|
108
|
+
@current = @next
|
109
|
+
fill_next
|
110
|
+
end
|
111
|
+
|
112
|
+
def next
|
113
|
+
result = @current
|
114
|
+
@current = @next
|
115
|
+
fill_next
|
116
|
+
return result
|
117
|
+
end
|
118
|
+
|
119
|
+
def reorder_events(start_to_completion, completion_to_start, last_decision_index)
|
120
|
+
reordered = []
|
121
|
+
reordered.concat(completion_to_start.slice(0, last_decision_index + 1)) if last_decision_index >= 0
|
122
|
+
reordered.concat(start_to_completion)
|
123
|
+
if completion_to_start.length > last_decision_index + 1
|
124
|
+
reordered.concat(completion_to_start.slice((last_decision_index + 1)..-1))
|
125
|
+
end
|
126
|
+
return reordered.flatten
|
127
|
+
end
|
128
|
+
|
129
|
+
def fill_next
|
130
|
+
decision_task_timed_out = false
|
131
|
+
decision_start_to_completion_events, decision_completion_to_start_events = [], []
|
132
|
+
next_replay_current_time_milliseconds = -1
|
133
|
+
last_decision_index = -1
|
134
|
+
while @events.events.length > 0
|
135
|
+
event = @events.events.shift
|
136
|
+
event_type = event.event_type.to_sym
|
137
|
+
case event_type
|
138
|
+
when :DecisionTaskCompleted
|
139
|
+
#TODO get execution context
|
140
|
+
#TODO updateWorkflowContextDataAndComponentVersions
|
141
|
+
concurrent_to_decision = false
|
142
|
+
when :DecisionTaskStarted
|
143
|
+
next_replay_current_time_milliseconds = event.created_at
|
144
|
+
if decision_task_timed_out
|
145
|
+
@current.decision_events.concat(decision_start_to_completion_events)
|
146
|
+
decision_start_to_completion_events = []
|
147
|
+
decision_task_timed_out = false
|
148
|
+
else
|
149
|
+
break
|
150
|
+
end
|
151
|
+
when :DecisionTaskTimedOut
|
152
|
+
decision_task_timed_out = true
|
153
|
+
when :DecisionTaskScheduled
|
154
|
+
# pass
|
155
|
+
when :MarkerRecorded
|
156
|
+
# pass
|
157
|
+
else
|
158
|
+
if concurrent_to_decision
|
159
|
+
decision_start_to_completion_events << event
|
160
|
+
else
|
161
|
+
if is_decision_event? event_type
|
162
|
+
last_decision_index = decision_completion_to_start_events.length
|
163
|
+
end
|
164
|
+
decision_completion_to_start_events << event
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
next_events = reorder_events(decision_start_to_completion_events, decision_completion_to_start_events, last_decision_index)
|
169
|
+
@next = SingleDecisionData.new(next_events, next_replay_current_time_milliseconds, @workflow_context_data )
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,82 @@
|
|
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
|
+
# Creates a new {WorkflowClient} instance
|
20
|
+
#
|
21
|
+
# @param service
|
22
|
+
# A {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow.html SWF service} reference. This is usually
|
23
|
+
# created with:
|
24
|
+
#
|
25
|
+
# swf = AWS::SimpleWorkflow.new
|
26
|
+
#
|
27
|
+
# @param domain
|
28
|
+
# The SWF {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/Domain.html Domain} to use for this
|
29
|
+
# workflow client. This is usually created on the service object, such as:
|
30
|
+
#
|
31
|
+
# domain = swf.domains.create('my-domain', 10)
|
32
|
+
#
|
33
|
+
# or retrieved from it (for existing domains):
|
34
|
+
#
|
35
|
+
# domain = swf.domains['my-domain']
|
36
|
+
#
|
37
|
+
# @param [Hash, StartWorkflowOptions] block
|
38
|
+
# A hash of options to start the workflow.
|
39
|
+
#
|
40
|
+
def workflow_client(service = nil, domain = nil, &block)
|
41
|
+
AWS::Flow.send(:workflow_client, service, domain, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Execute a block with retries within a workflow context.
|
45
|
+
#
|
46
|
+
# @param options
|
47
|
+
# The {RetryOptions} to use.
|
48
|
+
#
|
49
|
+
# @param block
|
50
|
+
# The block to execute.
|
51
|
+
#
|
52
|
+
def with_retry(options = {}, &block)
|
53
|
+
raise "with_retry can only be used inside a workflow context!" if Utilities::is_external
|
54
|
+
retry_options = RetryOptions.new(options)
|
55
|
+
retry_policy = RetryPolicy.new(retry_options.retry_function, retry_options)
|
56
|
+
async_retrying_executor = AsyncRetryingExecutor.new(retry_policy, self.decision_context.workflow_clock, retry_options.return_on_start)
|
57
|
+
future = async_retrying_executor.execute(lambda { block.call })
|
58
|
+
Utilities::drill_on_future(future) unless retry_options.return_on_start
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
def self.workflow_client(service = nil, domain = nil, &block)
|
64
|
+
options = Utilities::interpret_block_for_options(StartWorkflowOptions, block)
|
65
|
+
if ! Utilities::is_external
|
66
|
+
service = AWS::SimpleWorkflow.new
|
67
|
+
# So, we probably shouldn't be doing this, but we need to slightly
|
68
|
+
# redesign where this is available from
|
69
|
+
domain = FlowFiber.current[:decision_context].workflow_context.decision_task.workflow_execution.domain
|
70
|
+
else
|
71
|
+
if service.nil? || domain.nil?
|
72
|
+
raise "You must provide both a service and domain when using workflow client in an external setting"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
workflow_class_name = options.from_class || options.workflow_name
|
77
|
+
workflow_class = get_const(workflow_class_name) rescue nil
|
78
|
+
WorkflowClient.new(service, domain, workflow_class, options)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,607 @@
|
|
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
|
+
# The base class for option defaults in the AWS Flow Framework for Ruby.
|
20
|
+
class Defaults
|
21
|
+
def method_missing(method_name, *args, &block)
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The base class for all options classes in the AWS Flow Framework for Ruby.
|
27
|
+
class Options
|
28
|
+
extend Utilities::UpwardLookups
|
29
|
+
include Utilities::UpwardLookups::InstanceMethods
|
30
|
+
def method_missing(method_name, *args, &block)
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the default classes on a child class (a class derived from {Options}).
|
35
|
+
def self.inherited(child)
|
36
|
+
child.precursors ||= []
|
37
|
+
default_classes = child.ancestors.map do |precursor|
|
38
|
+
precursor.default_classes if precursor.methods.map(&:to_sym).include? :default_classes
|
39
|
+
end.compact.flatten
|
40
|
+
child.instance_variable_set("@default_classes", default_classes)
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
# The set of default options. These are used when `use_defaults` is set to `true` on {#initialize}.
|
45
|
+
attr_accessor :default_classes
|
46
|
+
end
|
47
|
+
|
48
|
+
# Merges specified options with the set of options already held by the class, and returns the result.
|
49
|
+
#
|
50
|
+
# @return [Hash]
|
51
|
+
# The merged set of options, defined as a hash.
|
52
|
+
#
|
53
|
+
# @param [Options] options
|
54
|
+
# An {Options}-derived class containing a set of options to use if this instance has no options, or options to
|
55
|
+
# add to this one if this instance already has options.
|
56
|
+
#
|
57
|
+
# @param [Hash] extra_to_add
|
58
|
+
# A hash containing extra options to merge with the options held by the class and those provided in the
|
59
|
+
# +options+ parameter.
|
60
|
+
#
|
61
|
+
def get_options(options, extra_to_add = {})
|
62
|
+
options = self.class.held_properties.compact if options.empty?
|
63
|
+
set_options = options.select {|option| self.send(option) != nil && self.send(option) != "" }
|
64
|
+
option_values = set_options.map {|option| self.send(option) == Float::INFINITY ? "NONE" : self.send(option) }
|
65
|
+
result = Hash[set_options.zip(option_values)]
|
66
|
+
result.merge(extra_to_add)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new {Options} instance.
|
70
|
+
#
|
71
|
+
# @param [Hash] hash
|
72
|
+
# A hash of values to use as the default options for this instance. The members of this hash are defined by
|
73
|
+
# classes derived from {Options}.
|
74
|
+
#
|
75
|
+
# @param [true, false] use_defaults
|
76
|
+
# In derived classes, this parameter is used to tell the constructor to use the set of default options as the
|
77
|
+
# runtime options. This has no effect in the base {Options} class.
|
78
|
+
#
|
79
|
+
def initialize(hash={}, use_defaults = false)
|
80
|
+
@precursors ||= []
|
81
|
+
hash.each_pair do |key, val|
|
82
|
+
if self.methods.map(&:to_sym).include? "#{key}=".to_sym
|
83
|
+
self.send("#{key}=", val)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
property(:from_class)
|
89
|
+
property(:prefix_name, [lambda {|x| raise "You cannot have a . in your prefix name" if x.include? "."; x}, lambda(&:to_s)])
|
90
|
+
property(:return_on_start, [lambda {|x| x == true}])
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
class WorkerDefaults < Defaults
|
95
|
+
def use_forking; true; end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Options for Activity and Workflow workers.
|
99
|
+
#
|
100
|
+
# @!attribute logger
|
101
|
+
# The logger to use for the worker.
|
102
|
+
#
|
103
|
+
# @!attribute poller_workers
|
104
|
+
# The logger to use for the worker.
|
105
|
+
#
|
106
|
+
# @!attribute execution_workers
|
107
|
+
# The logger to use for the worker.
|
108
|
+
#
|
109
|
+
class WorkerOptions < Options
|
110
|
+
property(:logger, [])
|
111
|
+
# At current, we only support one poller per worker
|
112
|
+
# property(:poller_workers, [lambda(&:to_i)])
|
113
|
+
property(:execution_workers, [lambda(&:to_i)])
|
114
|
+
property(:use_forking, [lambda {|x| x == true}] )
|
115
|
+
default_classes << WorkerDefaults.new
|
116
|
+
end
|
117
|
+
|
118
|
+
# Options for WorkflowClient#signal_workflow_execution.
|
119
|
+
#
|
120
|
+
# @!attribute control
|
121
|
+
# Optional data attached to the signal that can be used by the workflow execution.
|
122
|
+
#
|
123
|
+
# @!attribute domain
|
124
|
+
# *Required*. The name of the domain containing the workflow execution to signal.
|
125
|
+
#
|
126
|
+
# @!attribute input
|
127
|
+
# Data to attach to the WorkflowExecutionSignaled event in the target workflow execution's history.
|
128
|
+
#
|
129
|
+
# @!attribute run_id
|
130
|
+
# The runId of the workflow execution to signal.
|
131
|
+
#
|
132
|
+
# @!attribute signal_name
|
133
|
+
# *Required*. The name of the signal. This name must be meaningful to the target workflow.
|
134
|
+
#
|
135
|
+
# @!attribute workflow_id
|
136
|
+
# *Required*. The workflowId of the workflow execution to signal.
|
137
|
+
#
|
138
|
+
class SignalWorkflowOptions < Options
|
139
|
+
properties(:input, :signal_name, :run_id, :workflow_id, :control, :domain)
|
140
|
+
|
141
|
+
# Gets a hash containing the held options.
|
142
|
+
def get_full_options
|
143
|
+
result = {}
|
144
|
+
SignalWorkflowOptions.held_properties.each do |option|
|
145
|
+
result[option] = self.send(option) if self.send(option) && self.send(option) != ""
|
146
|
+
end
|
147
|
+
result
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Defaults for {RetryOptions}
|
152
|
+
class RetryDefaults < Defaults
|
153
|
+
# The default maximum number of attempts to make before the task is marked as failed.
|
154
|
+
def maximum_attempts; FlowConstants.exponential_retry_maximum_attempts; end
|
155
|
+
# The default retry function to use.
|
156
|
+
def retry_function; FlowConstants.exponential_retry_function; end
|
157
|
+
def exceptions_to_include; FlowConstants.exponential_retry_exceptions_to_include; end
|
158
|
+
def exceptions_to_exclude; FlowConstants.exponential_retry_exceptions_to_exclude; end
|
159
|
+
def should_jitter; FlowConstants.should_jitter; end
|
160
|
+
def jitter_function; FlowConstants.jitter_function; end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Retry options used with {GenericClient#retry} and {ActivityClient#exponential_retry}
|
164
|
+
class RetryOptions < Options
|
165
|
+
property(:is_retryable_function, [])
|
166
|
+
property(:exceptions_to_allow, [])
|
167
|
+
property(:maximum_attempts, [lambda {|x| x == "NONE" ? "NONE" : x.to_i}])
|
168
|
+
property(:maximum_retry_interval_seconds, [lambda {|x| x == "NONE" ? "NONE" : x.to_i}])
|
169
|
+
property(:exceptions_to_retry, [])
|
170
|
+
property(:exceptions_to_exclude, [])
|
171
|
+
property(:exceptions_to_include, [])
|
172
|
+
property(:jitter_function, [])
|
173
|
+
property(:should_jitter, [lambda {|x| x == true}])
|
174
|
+
property(:retries_per_exception, [])
|
175
|
+
property(:retry_function, [])
|
176
|
+
default_classes << RetryDefaults.new
|
177
|
+
|
178
|
+
# Creates a new {RetryOptions} instance.
|
179
|
+
#
|
180
|
+
# @param [Hash] hash The set of default RetryOptions.
|
181
|
+
#
|
182
|
+
# @option hash :is_retryable_function
|
183
|
+
# The function used to test if the activity is retryable.
|
184
|
+
#
|
185
|
+
# @option hash :exceptions_to_allow [Integer]
|
186
|
+
# The number of exceptions to allow
|
187
|
+
#
|
188
|
+
# @option hash :maximum_attempts [Integer]
|
189
|
+
# The maximum number of attempts to make before the task is marked as failed.
|
190
|
+
#
|
191
|
+
# @option hash :maximum_retry_interval_seconds [Integer]
|
192
|
+
# The maximum retry interval, in seconds.
|
193
|
+
#
|
194
|
+
# @option hash :exceptions_to_retry [Array]
|
195
|
+
# The list of exceptions that will cause a retry attempt.
|
196
|
+
#
|
197
|
+
# @option hash :exceptions_to_exclude [Array]
|
198
|
+
# The list of exceptions to exclude from retry.
|
199
|
+
#
|
200
|
+
# @option hash :jitter_function
|
201
|
+
# The jitter function used to modify the actual retry time.
|
202
|
+
#
|
203
|
+
# @option hash :retries_per_exception [Integer]
|
204
|
+
# The number of retries to make per exception.
|
205
|
+
#
|
206
|
+
# @option hash :retry_function
|
207
|
+
# The retry function to use.
|
208
|
+
#
|
209
|
+
# @param [true, false] use_defaults
|
210
|
+
# If set to `true`, the default options specified will be used as the runtime options.
|
211
|
+
#
|
212
|
+
def initialize(hash={}, use_defaults=false)
|
213
|
+
super(hash, use_defaults)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Tests whether or not this activity can be retried based on the `:exceptions_to_retry` and
|
217
|
+
# `:exceptions_to_exclude` options.
|
218
|
+
#
|
219
|
+
# @param [Object] failure
|
220
|
+
# The failure type to test.
|
221
|
+
#
|
222
|
+
# @return [true, false]
|
223
|
+
# Returns `true` if the activity can be retried; `false` otherwise.
|
224
|
+
#
|
225
|
+
def isRetryable(failure)
|
226
|
+
#TODO stuff about checking for a DecisionException, getting cause if so
|
227
|
+
is_retryable = false
|
228
|
+
is_retryable = @exceptions_to_retry.reject {|exception| failure.class <= exception}.empty?
|
229
|
+
if is_retryable
|
230
|
+
is_retryable = @exceptions_to_exclude.select{|exception| failure.class <= exception}.empty?
|
231
|
+
end
|
232
|
+
return is_retryable
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Exponential retry options for the {ActivityClient#exponential_retry} method.
|
237
|
+
class ExponentialRetryOptions < RetryOptions
|
238
|
+
# The backoff coefficient to use. This is a floating point value that is multiplied with the current retry
|
239
|
+
# interval after every retry attempt. The default value is 2.0, which means that each retry will take twice as
|
240
|
+
# long as the previous.
|
241
|
+
attr_accessor :backoff_coefficient
|
242
|
+
|
243
|
+
# The retry expiration interval, in seconds. This will be increased after every retry attempt by the factor
|
244
|
+
# provided in +backoff_coefficient+.
|
245
|
+
attr_accessor :retry_expiration_interval_seconds
|
246
|
+
|
247
|
+
def next_retry_delay_seconds(first_attmept, recorded_failure, attempts)
|
248
|
+
raise IllegalArgumentException "Attempt number is #{attempts}, when it needs to be greater than 1"
|
249
|
+
if @maximum_attempts
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Defaults for WorkflowOptions
|
255
|
+
class WorkflowDefaults < Defaults
|
256
|
+
|
257
|
+
# The default task start-to-close timeout duration.
|
258
|
+
def task_start_to_close_timeout; 30; end
|
259
|
+
|
260
|
+
# The default child workflow policy
|
261
|
+
def child_policy; :TERMINATE; end
|
262
|
+
|
263
|
+
# Returns a list of tags (currently an empty array).
|
264
|
+
def tag_list; []; end
|
265
|
+
|
266
|
+
def data_converter; FlowConstants.default_data_converter; end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Options for workflows
|
270
|
+
#
|
271
|
+
# @!attribute child_policy
|
272
|
+
# The optional policy to use for the child workflow executions when a workflow execution of this type is
|
273
|
+
# terminated, by calling the TerminateWorkflowExecution action explicitly or due to an expired timeout. This can
|
274
|
+
# be overridden when starting a workflow execution using the StartWorkflowExecution action or the
|
275
|
+
# StartChildWorkflowExecution Decision. The supported child policies are:
|
276
|
+
#
|
277
|
+
# * *TERMINATE*: the child executions will be terminated.
|
278
|
+
# * *REQUEST_CANCEL*: a request to cancel will be attempted for each child execution by recording a
|
279
|
+
# WorkflowExecutionCancelRequested event in its history. It is up to the decider to take appropriate actions
|
280
|
+
# when it receives an execution history with this event.
|
281
|
+
# * *ABANDON*: no action will be taken. The child executions will continue to run.
|
282
|
+
#
|
283
|
+
# The default is TERMINATE.
|
284
|
+
#
|
285
|
+
# @!attribute execution_method
|
286
|
+
# TBD
|
287
|
+
#
|
288
|
+
# @!attribute execution_start_to_close_timeout
|
289
|
+
# The optional maximum duration, specified when registering the workflow type, for executions of this workflow
|
290
|
+
# type. This default can be overridden when starting a workflow execution using the StartWorkflowExecution action
|
291
|
+
# or the StartChildWorkflowExecution decision.
|
292
|
+
#
|
293
|
+
# The valid values are integers greater than or equal to 0. An integer value can be used to specify the duration
|
294
|
+
# in seconds while NONE can be used to specify unlimited duration.
|
295
|
+
#
|
296
|
+
# @!attribute input
|
297
|
+
# A string of up to 32768 characters, to be provided to the workflow execution.
|
298
|
+
#
|
299
|
+
# @!attribute tag_list
|
300
|
+
# The list of tags to associate with the child workflow execution. A maximum of five tags can be specified. You
|
301
|
+
# can list workflow executions with a specific tag by calling ListOpenWorkflowExecutions or
|
302
|
+
# ListClosedWorkflowExecutions and specifying a TagFilter.
|
303
|
+
#
|
304
|
+
# @!attribute task_list
|
305
|
+
# The optional task list, specified when registering the workflow type, for decisions tasks scheduled for workflow
|
306
|
+
# executions of this type. This default can be overridden when starting a workflow execution using the
|
307
|
+
# StartWorkflowExecution action or the StartChildWorkflowExecution Decision.
|
308
|
+
#
|
309
|
+
# @!attribute task_start_to_close_timeout
|
310
|
+
# The optional maximum duration, specified when registering the workflow type, that a decision task for executions
|
311
|
+
# of this workflow type might take before returning completion or failure. If the task does not close in the
|
312
|
+
# specified time then the task is automatically timed out and rescheduled. If the decider eventually reports a
|
313
|
+
# completion or failure, it is ignored. This default can be overridden when starting a workflow execution using
|
314
|
+
# the StartWorkflowExecution action or the StartChildWorkflowExecution Decision.
|
315
|
+
#
|
316
|
+
# The valid values are integers greater than or equal to 0. An integer value can be used to specify the duration
|
317
|
+
# in seconds while NONE can be used to specify unlimited duration.
|
318
|
+
#
|
319
|
+
# The default is 30.
|
320
|
+
#
|
321
|
+
# @!attribute version
|
322
|
+
# The version of the Workflow. If you update any of these options, you must update the version.
|
323
|
+
#
|
324
|
+
# @!attribute workflow_id
|
325
|
+
# *Required*. The workflow id of the workflow execution.
|
326
|
+
#
|
327
|
+
# The specified string must not start or end with whitespace. It must not contain a `:` (colon), `/` (slash), `|`
|
328
|
+
# (vertical bar), or any control characters (\u0000-\u001f | \u007f - \u009f). Also, it must not contain the
|
329
|
+
# literal string "arn".
|
330
|
+
#
|
331
|
+
class WorkflowOptions < Options
|
332
|
+
properties(:version, :input, :workflow_id, :execution_start_to_close_timeout, :task_start_to_close_timeout, :task_list, :execution_method)
|
333
|
+
property(:tag_list, [])
|
334
|
+
property(:child_policy, [lambda(&:to_s), lambda(&:upcase)])
|
335
|
+
property(:data_converter, [])
|
336
|
+
default_classes << WorkflowDefaults.new
|
337
|
+
|
338
|
+
# Returns a hash containing the runtime workflow options.
|
339
|
+
#
|
340
|
+
# @return [Hash] a hash of options with corresponding values.
|
341
|
+
#
|
342
|
+
def get_full_options
|
343
|
+
result = {}
|
344
|
+
usable_properties = self.class.held_properties
|
345
|
+
usable_properties.delete(:from_class)
|
346
|
+
usable_properties.each do |option|
|
347
|
+
result[option] = self.send(option) if self.send(option) && self.send(option) != ""
|
348
|
+
end
|
349
|
+
result
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
class WorkflowOptionsWithDefaults < WorkflowOptions
|
354
|
+
properties(:default_task_start_to_close_timeout, :default_execution_start_to_close_timeout, :default_task_list)
|
355
|
+
property(:default_child_policy, [lambda(&:to_s), lambda(&:upcase)])
|
356
|
+
end
|
357
|
+
|
358
|
+
# Options for #start_workflow
|
359
|
+
#
|
360
|
+
# @!attribute workflow_name
|
361
|
+
# The name of this workflow.
|
362
|
+
#
|
363
|
+
# @!attribute from_class
|
364
|
+
# If present, options from the specified class will be used as the workflow execution options.
|
365
|
+
#
|
366
|
+
class StartWorkflowOptions < WorkflowOptions
|
367
|
+
properties(:workflow_name, :from_class)
|
368
|
+
end
|
369
|
+
|
370
|
+
# Options for {AsyncDecider#continue_as_new_workflow} and {Workflows.InstanceMethods#continue_as_new}.
|
371
|
+
#
|
372
|
+
class ContinueAsNewOptions < WorkflowOptions
|
373
|
+
end
|
374
|
+
|
375
|
+
# Defaults for the {ActivityOptions} class
|
376
|
+
class ActivityDefaults < Defaults
|
377
|
+
|
378
|
+
# The default Schedule to Close timeout for activity tasks. This timeout represents the time, in seconds, between
|
379
|
+
# when the activity task is first scheduled to when it is closed (whether due to success, failure, or a timeout).
|
380
|
+
#
|
381
|
+
# This default can be overridden when scheduling an activity task. You can set this value to "NONE" to imply no
|
382
|
+
# timeout value.
|
383
|
+
#
|
384
|
+
def default_task_schedule_to_close_timeout; Float::INFINITY; end
|
385
|
+
|
386
|
+
# The default maximum time in seconds before which a worker processing a task of this type must report progress.
|
387
|
+
# If the timeout is exceeded, the activity task is automatically timed out. If the worker subsequently attempts to
|
388
|
+
# record a heartbeat or returns a result, it will be ignored.
|
389
|
+
#
|
390
|
+
# This default can be overridden when scheduling an activity task. You can set this value to "NONE" to imply no
|
391
|
+
# timeout value.
|
392
|
+
#
|
393
|
+
def default_task_heartbeat_timeout; Float::INFINITY; end
|
394
|
+
|
395
|
+
# The default Schedule to Close timeout. This timeout represents the time between when the activity task is first
|
396
|
+
# scheduled to when it is closed (whether due to success, failure, or a timeout).
|
397
|
+
#
|
398
|
+
# This default can be overridden when scheduling an activity task. You can set this value to "NONE" to imply no
|
399
|
+
# timeout value.
|
400
|
+
#
|
401
|
+
def schedule_to_close_timeout; Float::INFINITY; end
|
402
|
+
|
403
|
+
# The default maximum time before which a worker processing a task of this type must report progress. If the
|
404
|
+
# timeout is exceeded, the activity task is automatically timed out. If the worker subsequently attempts to record
|
405
|
+
# a heartbeat or returns a result, it will be ignored. This default can be overridden when scheduling an activity
|
406
|
+
# task.
|
407
|
+
#
|
408
|
+
# This default can be overridden when scheduling an activity task. You can set this value to "NONE" to imply no
|
409
|
+
# timeout value.
|
410
|
+
#
|
411
|
+
def heartbeat_timeout; Float::INFINITY; end
|
412
|
+
|
413
|
+
def data_converter; FlowConstants.default_data_converter; end
|
414
|
+
end
|
415
|
+
|
416
|
+
|
417
|
+
# Options to use on an activity or decider. The following options are defined:
|
418
|
+
#
|
419
|
+
# @!attribute default_task_heartbeat_timeout
|
420
|
+
#
|
421
|
+
# The optional default maximum time, specified when registering the activity type, before which a worker
|
422
|
+
# processing a task must report progress by calling
|
423
|
+
# {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SimpleWorkflow/ActivityTask.html#record_heartbeat!-instance_method
|
424
|
+
# record_heartbeat} on the ActivityTask.
|
425
|
+
#
|
426
|
+
# You can override this default when scheduling a task through the ScheduleActivityTask Decision. If the
|
427
|
+
# activity worker subsequently attempts to record a heartbeat or returns a result, the activity worker receives
|
428
|
+
# an UnknownResource fault. In this case, Amazon SWF no longer considers the activity task to be valid; the
|
429
|
+
# activity worker should clean up the activity task.
|
430
|
+
#
|
431
|
+
# The valid values are integers greater than or equal to zero. An integer value can be used to specify the
|
432
|
+
# duration in seconds while "NONE" can be used to specify unlimited duration.
|
433
|
+
#
|
434
|
+
# @!attribute default_task_list
|
435
|
+
#
|
436
|
+
# The optional default task list specified for this activity type at registration. This default task list is
|
437
|
+
# used if a task list is not provided when a task is scheduled through the ScheduleActivityTask decision. You
|
438
|
+
# can override this default when scheduling a task through the ScheduleActivityTask decision.
|
439
|
+
#
|
440
|
+
# @!attribute default_task_schedule_to_close_timeout
|
441
|
+
#
|
442
|
+
# The optional default maximum duration, specified when registering the activity type, for tasks of this
|
443
|
+
# activity type. You can override this default when scheduling a task through the ScheduleActivityTask Decision.
|
444
|
+
#
|
445
|
+
# The valid values are integers greater than or equal to zero, or the string "NONE". An integer value can be
|
446
|
+
# used to specify the duration in seconds while "NONE" is be used to specify *unlimited* duration.
|
447
|
+
#
|
448
|
+
# @!attribute default_task_schedule_to_start_timeout
|
449
|
+
#
|
450
|
+
# The optional default maximum duration, specified when registering the activity type, that a task of an
|
451
|
+
# activity type can wait before being assigned to a worker. You can override this default when scheduling a task
|
452
|
+
# through the ScheduleActivityTask decision.
|
453
|
+
#
|
454
|
+
# @!attribute default_task_start_to_close_timeout
|
455
|
+
#
|
456
|
+
# The optional default maximum duration for tasks of an activity type specified when registering the activity
|
457
|
+
# type. You can override this default when scheduling a task through the ScheduleActivityTask decision.
|
458
|
+
class ActivityOptions < Options
|
459
|
+
# The default options for the activity. These can be specified when creating a new ActivityOptions instance.
|
460
|
+
#
|
461
|
+
class << self
|
462
|
+
attr_reader :default_options, :runtime_options
|
463
|
+
end
|
464
|
+
properties(:default_task_heartbeat_timeout, :default_task_list, :default_task_schedule_to_close_timeout, :default_task_schedule_to_start_timeout, :default_task_start_to_close_timeout, :heartbeat_timeout, :task_list, :schedule_to_close_timeout, :schedule_to_start_timeout, :start_to_close_timeout, :version, :input)
|
465
|
+
property(:manual_completion, [lambda {|x| x == true}])
|
466
|
+
property(:data_converter, [])
|
467
|
+
|
468
|
+
default_classes << ActivityDefaults.new
|
469
|
+
|
470
|
+
# Gets the activity prefix name
|
471
|
+
# @return [String] the activity name
|
472
|
+
def activity_name
|
473
|
+
@prefix_name
|
474
|
+
end
|
475
|
+
|
476
|
+
# Sets the activity prefix name
|
477
|
+
# @param [String] value the activity name to set
|
478
|
+
def activity_name=(value)
|
479
|
+
@prefix_name = value
|
480
|
+
end
|
481
|
+
|
482
|
+
# Creates a new set of ActivityOptions
|
483
|
+
#
|
484
|
+
# @param [Hash] default_options
|
485
|
+
# A set of ActivityOptions to use as the default values.
|
486
|
+
#
|
487
|
+
# @option default_options [Integer] :heartbeat_timeout
|
488
|
+
# The optional default maximum time, specified when registering the activity type, before which a worker
|
489
|
+
# processing a task must report progress by calling RecordActivityTaskHeartbeat. You can override this default
|
490
|
+
# when scheduling a task through the ScheduleActivityTask Decision. If the activity worker subsequently attempts
|
491
|
+
# to record a heartbeat or returns a result, the activity worker receives an UnknownResource fault. In this
|
492
|
+
# case, Amazon SWF no longer considers the activity task to be valid; the activity worker should clean up the
|
493
|
+
# activity task.
|
494
|
+
#
|
495
|
+
# @option default_options [Integer] :schedule_to_close_timeout
|
496
|
+
# The optional default maximum duration, specified when registering the activity type, for tasks of this
|
497
|
+
# activity type. You can override this default when scheduling a task through the ScheduleActivityTask Decision.
|
498
|
+
#
|
499
|
+
# @option default_options [Integer] :schedule_to_start_timeout
|
500
|
+
# The optional default maximum duration, specified when registering the activity type, that a task of an
|
501
|
+
# activity type can wait before being assigned to a worker. You can override this default when scheduling a task
|
502
|
+
# through the ScheduleActivityTask Decision.
|
503
|
+
#
|
504
|
+
# @option default_options [Integer] :start_to_close_timeout
|
505
|
+
# The optional default maximum duration for tasks of an activity type specified when registering the activity
|
506
|
+
# type. You can override this default when scheduling a task through the ScheduleActivityTask Decision.
|
507
|
+
#
|
508
|
+
# @option default_options [Array] :task_list
|
509
|
+
# The optional default task list specified for this activity type at registration. This default task list is
|
510
|
+
# used if a task list is not provided when a task is scheduled through the ScheduleActivityTask Decision. You
|
511
|
+
# can override this default when scheduling a task through the ScheduleActivityTask Decision.
|
512
|
+
#
|
513
|
+
# @option default_options [String] :version
|
514
|
+
# The version of this Activity. If you change any other options on the activity, you must also change the
|
515
|
+
# version.
|
516
|
+
#
|
517
|
+
# @param [true, false] use_defaults
|
518
|
+
# Set to `true` to use the pre-defined default ActivityOptions.
|
519
|
+
#
|
520
|
+
def initialize(default_options={}, use_defaults=false)
|
521
|
+
if default_options.keys.include? :exponential_retry
|
522
|
+
@_exponential_retry = ExponentialRetryOptions.new(default_options[:exponential_retry])
|
523
|
+
end
|
524
|
+
super(default_options, use_defaults)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Retrieves the runtime options for this Activity. The runtime options returned are:
|
528
|
+
#
|
529
|
+
# * :heartbeat_timeout
|
530
|
+
# * :task_list
|
531
|
+
# * :schedule_to_close_timeout
|
532
|
+
# * :schedule_to_start_timeout
|
533
|
+
# * :start_to_close_timeout
|
534
|
+
#
|
535
|
+
# For a description of each of these options, see {#initialize}.
|
536
|
+
#
|
537
|
+
# @return [Hash]
|
538
|
+
# The runtime option names and their current values.
|
539
|
+
#
|
540
|
+
def get_runtime_options
|
541
|
+
result = get_options([:heartbeat_timeout, :task_list, :schedule_to_close_timeout, :schedule_to_start_timeout, :start_to_close_timeout])
|
542
|
+
default_options = get_options([:default_task_heartbeat_timeout, :default_task_schedule_to_close_timeout, :default_task_schedule_to_start_timeout, :default_task_start_to_close_timeout])
|
543
|
+
default_option_keys, default_option_values = default_options.keys, default_options.values
|
544
|
+
default_option_keys.map! { |option| option.to_s.gsub(/default_task_/, "").to_sym }
|
545
|
+
default_hash = Hash[default_option_keys.zip(default_option_values)]
|
546
|
+
default_hash.merge(result)
|
547
|
+
end
|
548
|
+
|
549
|
+
property(:_exponential_retry, [])
|
550
|
+
|
551
|
+
# Retries the supplied block with exponential retry logic.
|
552
|
+
#
|
553
|
+
# @param [Hash] block
|
554
|
+
# A hash of ExponentialRetryOptions.
|
555
|
+
#
|
556
|
+
def exponential_retry(&block)
|
557
|
+
retry_options = Utilities::interpret_block_for_options(ExponentialRetryOptions, block)
|
558
|
+
@_exponential_retry = retry_options
|
559
|
+
end
|
560
|
+
|
561
|
+
# Retrieves the runtime options for this Activity.
|
562
|
+
#
|
563
|
+
# @return [Hash]
|
564
|
+
# A hash containing the runtime option names and their current values.
|
565
|
+
#
|
566
|
+
def get_full_options
|
567
|
+
options_hash = self.get_runtime_options
|
568
|
+
[:task_list, :version, :_exponential_retry, :prefix_name, :return_on_start, :manual_completion, :data_converter].each do |attribute|
|
569
|
+
options_hash.merge!(attribute => self.send(attribute)) if self.send(attribute)
|
570
|
+
end
|
571
|
+
options_hash
|
572
|
+
end
|
573
|
+
|
574
|
+
# Retrieves the default options for this Activity.
|
575
|
+
#
|
576
|
+
# @return [Hash]
|
577
|
+
# A hash containing the default option names and their current values.
|
578
|
+
#
|
579
|
+
# The options retrieved are:
|
580
|
+
#
|
581
|
+
# * :default_task_heartbeat_timeout
|
582
|
+
# * :default_task_schedule_to_close_timeout
|
583
|
+
# * :default_task_schedule_to_start_timeout
|
584
|
+
# * :default_task_start_to_close_timeout
|
585
|
+
#
|
586
|
+
def get_default_options
|
587
|
+
get_options([:default_task_heartbeat_timeout, :default_task_schedule_to_close_timeout, :default_task_schedule_to_start_timeout, :default_task_start_to_close_timeout])
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
# Runtime options for an Activity.
|
592
|
+
class ActivityRuntimeOptions < ActivityOptions
|
593
|
+
|
594
|
+
# Creates a new set of runtime options based on a set of default options.
|
595
|
+
#
|
596
|
+
# @param [ActivityOptions] default_options
|
597
|
+
# The default {ActivityOptions} to use to set the values of the runtime options in this class.
|
598
|
+
#
|
599
|
+
# @param [true, false] use_defaults
|
600
|
+
# Set to `true` to use the default runtime options for the Activity.
|
601
|
+
#
|
602
|
+
def initialize(default_options = {}, use_defaults=false)
|
603
|
+
super(default_options, use_defaults)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|