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.
Files changed (62) hide show
  1. data/Gemfile +8 -0
  2. data/LICENSE.TXT +15 -0
  3. data/NOTICE.TXT +14 -0
  4. data/Rakefile +39 -0
  5. data/aws-flow-core/Gemfile +9 -0
  6. data/aws-flow-core/LICENSE.TXT +15 -0
  7. data/aws-flow-core/NOTICE.TXT +14 -0
  8. data/aws-flow-core/Rakefile +27 -0
  9. data/aws-flow-core/aws-flow-core.gemspec +12 -0
  10. data/aws-flow-core/lib/aws/flow.rb +26 -0
  11. data/aws-flow-core/lib/aws/flow/async_backtrace.rb +134 -0
  12. data/aws-flow-core/lib/aws/flow/async_scope.rb +195 -0
  13. data/aws-flow-core/lib/aws/flow/begin_rescue_ensure.rb +386 -0
  14. data/aws-flow-core/lib/aws/flow/fiber.rb +77 -0
  15. data/aws-flow-core/lib/aws/flow/flow_utils.rb +50 -0
  16. data/aws-flow-core/lib/aws/flow/future.rb +109 -0
  17. data/aws-flow-core/lib/aws/flow/implementation.rb +151 -0
  18. data/aws-flow-core/lib/aws/flow/simple_dfa.rb +85 -0
  19. data/aws-flow-core/lib/aws/flow/tasks.rb +405 -0
  20. data/aws-flow-core/test/aws/async_backtrace_spec.rb +41 -0
  21. data/aws-flow-core/test/aws/async_scope_spec.rb +118 -0
  22. data/aws-flow-core/test/aws/begin_rescue_ensure_spec.rb +665 -0
  23. data/aws-flow-core/test/aws/external_task_spec.rb +197 -0
  24. data/aws-flow-core/test/aws/factories.rb +52 -0
  25. data/aws-flow-core/test/aws/fiber_condition_variable_spec.rb +163 -0
  26. data/aws-flow-core/test/aws/fiber_spec.rb +78 -0
  27. data/aws-flow-core/test/aws/flow_spec.rb +255 -0
  28. data/aws-flow-core/test/aws/future_spec.rb +210 -0
  29. data/aws-flow-core/test/aws/rubyflow.rb +22 -0
  30. data/aws-flow-core/test/aws/simple_dfa_spec.rb +63 -0
  31. data/aws-flow-core/test/aws/spec_helper.rb +36 -0
  32. data/aws-flow.gemspec +13 -0
  33. data/lib/aws/decider.rb +67 -0
  34. data/lib/aws/decider/activity.rb +408 -0
  35. data/lib/aws/decider/activity_definition.rb +111 -0
  36. data/lib/aws/decider/async_decider.rb +673 -0
  37. data/lib/aws/decider/async_retrying_executor.rb +153 -0
  38. data/lib/aws/decider/data_converter.rb +40 -0
  39. data/lib/aws/decider/decider.rb +511 -0
  40. data/lib/aws/decider/decision_context.rb +60 -0
  41. data/lib/aws/decider/exceptions.rb +178 -0
  42. data/lib/aws/decider/executor.rb +149 -0
  43. data/lib/aws/decider/flow_defaults.rb +70 -0
  44. data/lib/aws/decider/generic_client.rb +178 -0
  45. data/lib/aws/decider/history_helper.rb +173 -0
  46. data/lib/aws/decider/implementation.rb +82 -0
  47. data/lib/aws/decider/options.rb +607 -0
  48. data/lib/aws/decider/state_machines.rb +373 -0
  49. data/lib/aws/decider/task_handler.rb +76 -0
  50. data/lib/aws/decider/task_poller.rb +207 -0
  51. data/lib/aws/decider/utilities.rb +187 -0
  52. data/lib/aws/decider/worker.rb +324 -0
  53. data/lib/aws/decider/workflow_client.rb +374 -0
  54. data/lib/aws/decider/workflow_clock.rb +104 -0
  55. data/lib/aws/decider/workflow_definition.rb +101 -0
  56. data/lib/aws/decider/workflow_definition_factory.rb +53 -0
  57. data/lib/aws/decider/workflow_enabled.rb +26 -0
  58. data/test/aws/decider_spec.rb +1299 -0
  59. data/test/aws/factories.rb +45 -0
  60. data/test/aws/integration_spec.rb +3108 -0
  61. data/test/aws/spec_helper.rb +23 -0
  62. metadata +138 -0
@@ -0,0 +1,22 @@
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
+ #!/usr/bin/ruby -wKU
17
+
18
+ def require_all(path)
19
+ Dir[File.join(File.dirname(__FILE__), path, "*.rb")].each {|f| require f}
20
+ end
21
+
22
+ require_all('rubyflow/')
@@ -0,0 +1,63 @@
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
+ describe SimpleDFA do
17
+ before(:each) do
18
+ class Tester
19
+ attr_accessor :trace
20
+
21
+ extend SimpleDFA
22
+ init(:start_state)
23
+
24
+ def initialize
25
+ @trace = []
26
+ end
27
+
28
+ add_transition(:start_state, :a) do |t|
29
+ t.trace << :start_to_second
30
+ t.current_state = :second_state
31
+ end
32
+ add_transition(:second_state, :b) do |t|
33
+ t.trace << :second_to_third
34
+ t.current_state = :third_state
35
+ end
36
+ add_transition(:third_state, :c) do |t|
37
+ t.trace << :third_to_start
38
+ t.current_state = :start_state
39
+ end
40
+ end
41
+ @this_dfa = Tester.new
42
+
43
+ end
44
+
45
+ it "ensures that consume works as expected" do
46
+ @this_dfa.consume(:a)
47
+ @this_dfa.trace.should == [:start_to_second]
48
+ @this_dfa.current_state.should == :second_state
49
+ end
50
+
51
+ it "ensures that define_general defines general transitions for a state" do
52
+ class Tester
53
+ define_general(:start_state) {|t| t.current_state = :new_state }
54
+ end
55
+ @this_dfa.consume(:c)
56
+ @this_dfa.current_state.should == :new_state
57
+ end
58
+
59
+ it "ensures that uncovered_transitions raises on those transitions" do
60
+ expect { @this_dfa.consume(:b) }.to raise_error
61
+ end
62
+
63
+ end
@@ -0,0 +1,36 @@
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 'rubygems'
17
+
18
+ require 'aws/flow'
19
+
20
+ include AWS::Flow::Core
21
+
22
+ Spec::DSL::Main.class_eval do
23
+ if method_defined? :context
24
+ undef :context
25
+ end
26
+ end
27
+
28
+ def constantize(camel_case_word)
29
+ names = camel_case_word.split('::')
30
+ names.shift if names.empty? || names.first.empty?
31
+ constant = Object
32
+ names.each do |name|
33
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
34
+ end
35
+ constant
36
+ end
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'aws-flow'
3
+ s.version = '1.0.0'
4
+ s.date = Time.now
5
+ s.summary = "AWS Flow Decider package decider"
6
+ s.description = "Library to provide the AWS Flow Framework for Ruby"
7
+ s.authors = "Michael Steger"
8
+ s.email = ''
9
+ s.files = `git ls-files`.split("\n")
10
+ s.require_paths << "lib/aws/"
11
+ s.add_dependency "aws-sdk", "~> 1"
12
+ s.add_dependency "aws-flow-core", "~> 1"
13
+ end
@@ -0,0 +1,67 @@
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
+ # @!visibility private
17
+ def require_all(path)
18
+ glob = File.join(path, "*.rb")
19
+ Dir[glob].each { |f| require f}
20
+ Dir[glob].map { |f| File.basename(f) }
21
+ end
22
+
23
+ require 'aws/flow'
24
+ include AWS::Flow::Core
25
+
26
+ require 'aws-sdk'
27
+ # Setting the user-agent as ruby-flow for all calls to the service
28
+ AWS.config(:user_agent_prefix => "ruby-flow")
29
+
30
+ #LOAD_PATH << File.dirname(File.expand_path(__FILE__))
31
+
32
+
33
+ require "aws/decider/utilities"
34
+ require "aws/decider/worker"
35
+ require 'aws/decider/generic_client'
36
+ require "aws/decider/async_retrying_executor"
37
+ require "aws/decider/activity_definition"
38
+ require "aws/decider/decider"
39
+ require "aws/decider/task_handler"
40
+ require "aws/decider/data_converter"
41
+ require "aws/decider/state_machines"
42
+ require "aws/decider/workflow_definition"
43
+
44
+ require "aws/decider/executor"
45
+ require "aws/decider/workflow_enabled"
46
+ require "aws/decider/options"
47
+ require "aws/decider/activity"
48
+ require "aws/decider/async_decider"
49
+ require "aws/decider/workflow_clock"
50
+ require "aws/decider/decision_context"
51
+ require "aws/decider/workflow_definition_factory"
52
+ require "aws/decider/workflow_client"
53
+ require "aws/decider/history_helper"
54
+ require "aws/decider/exceptions"
55
+ require "aws/decider/task_poller"
56
+ require "aws/decider/flow_defaults"
57
+ require "aws/decider/implementation"
58
+
59
+ # @!visibility private
60
+ def get_const(name)
61
+ name = name.split('::').reverse
62
+ current = Object
63
+ while ! name.empty?
64
+ current = current.const_get(name.pop)
65
+ end
66
+ current
67
+ end
@@ -0,0 +1,408 @@
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
+ # Represents information about an open request.
20
+ # @!visibility private
21
+ class OpenRequestInfo
22
+ attr_accessor :completion_handle, :result, :blocking_promise, :description, :run_id
23
+ end
24
+
25
+ class ActivityMetadata
26
+ attr_reader :activity_id
27
+ def initialize(activity_id); @activity_id = activity_id; end
28
+ end
29
+
30
+
31
+ # A generic activity client that can be used to perform standard activity actions.
32
+ class GenericActivityClient < GenericClient
33
+ # The data converter used for serializing/deserializing data when sending requests to and receiving results from
34
+ # workflow executions of this workflow type. By default, this is {YAMLDataConverter}.
35
+ attr_accessor :data_converter
36
+
37
+ # The decision helper used by the activity client.
38
+ attr_accessor :decision_helper
39
+
40
+ # A hash of ActivityRuntimeOptions for the activity client
41
+ attr_accessor :options
42
+
43
+ # Returns the default option class for the activity client, which is {ActivityRuntimeOptions}.
44
+ def self.default_option_class; ActivityRuntimeOptions; end
45
+
46
+ # Separates the activity name from the activity type at the point of the last (.) symbol.
47
+ #
48
+ # @param [String] name
49
+ # The name of the activity type.
50
+ #
51
+ def activity_name_from_activity_type(name)
52
+ return name.to_s.split(".").last.to_sym
53
+ end
54
+
55
+ # Creates a new GenericActivityClient instance.
56
+ #
57
+ # @param [DecisionHelper] decision_helper
58
+ # The decision helper to use for the activity client.
59
+ #
60
+ # @param [ActivityOptions] options ActivityOptions to set for the activity client.
61
+ #
62
+ def initialize(decision_helper, options)
63
+ @decision_helper = decision_helper
64
+ @options = options
65
+ @activity_option_map = @decision_helper.activity_options
66
+ @failure_map = {}
67
+ @data_converter ||= YAMLDataConverter.new
68
+ super
69
+ end
70
+
71
+ # Runs an activity given a name and block of options.
72
+ #
73
+ # @param method_name
74
+ # The name of the activity type to define
75
+ #
76
+ # @param args
77
+ # Arguments for the method
78
+ #
79
+ # @param block
80
+ # A block of {ActivityOptions}
81
+ #
82
+ def method_missing(method_name, *args, &block)
83
+ options = Utilities::interpret_block_for_options(ActivityOptions, block)
84
+ options = Utilities::merge_all_options(@options,
85
+ @activity_option_map[method_name.to_sym],
86
+ @option_map[method_name.to_sym],
87
+ options
88
+ )
89
+ new_options = ActivityOptions.new(options)
90
+
91
+ activity_type = ActivityType.new("#{new_options.prefix_name}.#{method_name.to_s}", new_options.version, new_options.get_default_options)
92
+ if new_options._exponential_retry
93
+ retry_function = new_options._exponential_retry.retry_function || FlowConstants.exponential_retry_function
94
+ new_options._exponential_retry.return_on_start ||= new_options.return_on_start
95
+ future = _retry_with_options(lambda { self.schedule_activity(activity_type.name, activity_type, args, new_options ) }, retry_function, new_options._exponential_retry, args)
96
+ return future if new_options.return_on_start
97
+ result = Utilities::drill_on_future(future)
98
+ else
99
+ result = schedule_activity(activity_type.name, activity_type, args, new_options)
100
+ end
101
+ result
102
+ end
103
+
104
+ # @!visibility private
105
+ def retry_alias_to_method(retry_alias)
106
+ retry_alias.to_s[/__(.*)_retry/, 1].to_sym
107
+ end
108
+
109
+ # @!visibility private
110
+ def method_to_retry_alias(method_name)
111
+ "#{__method_name.to_s + "_retry"}".to_sym
112
+ end
113
+
114
+ # Requests that the activity is canceled.
115
+ #
116
+ # @param [Future] to_cancel
117
+ # The Future for the task to be canceled.
118
+ #
119
+ def request_cancel_activity_task(to_cancel)
120
+ metadata = to_cancel.metadata
121
+ if ! metadata.respond_to? :activity_id
122
+ raise "You need to use a future obtained from an activity"
123
+ end
124
+ @decision_helper[metadata.activity_id].consume(:cancel)
125
+ end
126
+
127
+ # A handler for the ActivityClassCanceled event.
128
+ #
129
+ # @param [ActivityClassCanceled] event
130
+ # The event data.
131
+ #
132
+ def handle_activity_task_canceled(event)
133
+ activity_id = @decision_helper.get_activity_id(event.attributes[:scheduled_event_id])
134
+ @decision_helper[activity_id].consume(:handle_cancellation_event)
135
+ if @decision_helper[activity_id].done?
136
+ open_request = @decision_helper.scheduled_activities.delete(activity_id)
137
+ exception = CancellationException.new("Cancelled from ActivityTaskCanceledEvent", nil)
138
+ if ! open_request.nil?
139
+ open_request.completion_handle.fail(exception)
140
+ end
141
+ end
142
+ end
143
+
144
+ # A handler for the ActivityClassTimedOut event.
145
+ #
146
+ # @param [ActivityClassTimedOut] event
147
+ # The event data.
148
+ #
149
+ def handle_activity_task_timed_out(event)
150
+ activity_id = @decision_helper.get_activity_id(event.attributes[:scheduled_event_id])
151
+ activity_state_machine = @decision_helper[activity_id]
152
+ activity_state_machine.consume(:handle_completion_event)
153
+ if activity_state_machine.done?
154
+ open_request = @decision_helper.scheduled_activities.delete(activity_id)
155
+ if ! open_request.nil?
156
+ timeout_type = event.attributes[:timeout_type]
157
+ failure = ActivityTaskTimedOutException.new(event.id, activity_id, timeout_type, "Time out")
158
+ open_request.completion_handle.fail(failure)
159
+ end
160
+ end
161
+ end
162
+
163
+ # A handler for the {ActivityTaskFailed} event.
164
+ #
165
+ # @param [ActivityClassFailed] event
166
+ # The event data.
167
+ #
168
+ def handle_activity_task_failed(event)
169
+ attributes = event.attributes
170
+ activity_id = @decision_helper.get_activity_id(attributes[:scheduled_event_id])
171
+ @decision_helper[activity_id].consume(:handle_completion_event)
172
+ open_request_info = @decision_helper.scheduled_activities.delete(activity_id)
173
+ reason = attributes[:reason]
174
+ details = attributes[:details]
175
+ # TODO consider adding user_context to open request, and adding it here
176
+ # @decision_helper[@decision_helper.activity_scheduling_event_id_to_activity_id[event.attributes.scheduled_event_id]].attributes[:options].data_converter
177
+ failure = ActivityTaskFailedException.new(event.id, activity_id, reason, details)
178
+ open_request_info.completion_handle.fail(failure)
179
+ end
180
+
181
+ # A handler for the {ScheduleActivityTaskFailed} event.
182
+ #
183
+ # @param [ScheduleActivityTaskFailed] event
184
+ # The event data.
185
+ #
186
+ def handle_schedule_activity_task_failed(event)
187
+ attributes = event.attributes
188
+ activity_id = attributes[:activity_id]
189
+ open_request_info = @decision_helper.scheduled_activities.delete(activity_id)
190
+ activity_state_machine = @decision_helper[activity_id]
191
+ activity_state_machine.consume(:handle_initiation_failed_event)
192
+ if activity_state_machine.done?
193
+ # TODO Fail task correctly
194
+ failure = ScheduleActivityTaskFailedException.new(event.id, event.attributes.activity_type, activity_id, event.attributes.cause)
195
+ open_request_info.completion_handle.fail(failure)
196
+ end
197
+ end
198
+
199
+ # A handler for the {ActivityClassCompleted} event.
200
+ #
201
+ # @param [ActivityClassCompleted] event
202
+ # The event data.
203
+ #
204
+ def handle_activity_task_completed(event)
205
+ scheduled_id = event.attributes[:scheduled_event_id]
206
+ activity_id = @decision_helper.activity_scheduling_event_id_to_activity_id[scheduled_id]
207
+ @decision_helper[activity_id].consume(:handle_completion_event)
208
+ if @decision_helper[activity_id].done?
209
+ open_request = @decision_helper.scheduled_activities.delete(activity_id)
210
+ open_request.result = event.attributes[:result]
211
+ open_request.completion_handle.complete
212
+ end
213
+ end
214
+
215
+ # Schedules the named activity.
216
+ #
217
+ # @param [String] name
218
+ # The name of the activity to schedule.
219
+ #
220
+ # @param [String]
221
+ # activity_type The activity type for this scheduled activity.
222
+ #
223
+ # @param [Object]
224
+ # input Optional data passed to the activity.
225
+ #
226
+ # @param [ActivityOptions]
227
+ # options ActivityOptions to set for the scheduled activity.
228
+ #
229
+ def schedule_activity(name, activity_type, input, options)
230
+ options = Utilities::merge_all_options(@option_map[activity_name_from_activity_type(name)], options)
231
+ new_options = ActivityOptions.new(options)
232
+ output = Utilities::AddressableFuture.new
233
+ open_request = OpenRequestInfo.new
234
+ decision_id = @decision_helper.get_next_id(:Activity)
235
+ output._metadata = ActivityMetadata.new(decision_id)
236
+ error_handler do |t|
237
+ t.begin do
238
+ @data_converter = new_options.data_converter
239
+
240
+ #input = input.map { |input_part| @data_converter.dump input_part } unless input.nil?
241
+ input = @data_converter.dump input unless input.empty?
242
+ attributes = {}
243
+ new_options.input ||= input unless input.empty?
244
+ attributes[:options] = new_options
245
+ attributes[:activity_type] = activity_type
246
+ attributes[:decision_id] = decision_id
247
+ @completion_handle = nil
248
+ external_task do |t|
249
+ t.initiate_task do |handle|
250
+ open_request.completion_handle = handle
251
+
252
+ @decision_helper.scheduled_activities[decision_id.to_s] = open_request
253
+ @decision_helper[decision_id.to_s] = ActivityDecisionStateMachine.new(decision_id, attributes)
254
+ end
255
+ t.cancellation_handler do |this_handle, cause|
256
+ state_machine = @decision_helper[decision_id.to_s]
257
+ if state_machine.current_state == :created
258
+ open_request = @decision_helper.scheduled_activities.delete(decision_id.to_s)
259
+ open_request.completion_handle.complete
260
+ end
261
+ state_machine.consume(:cancel)
262
+ end
263
+ end
264
+ end
265
+ t.rescue(Exception) do |error|
266
+ @data_converter = new_options.data_converter
267
+ # If we have an ActivityTaskFailedException, then we should figure
268
+ # out what the cause was, and pull that out. If it's anything else,
269
+ # we should serialize the error, and stuff that into details, so
270
+ # that things above us can pull it out correctly. We don't have to
271
+ # do this for ActivityTaskFailedException, as the details is
272
+ # *already* serialized
273
+ if error.is_a? ActivityTaskFailedException
274
+ details = @data_converter.load(error.details)
275
+ error.cause = details
276
+ else
277
+ details = @data_converter.dump(error)
278
+ error.details = details
279
+ end
280
+ @failure_map[decision_id.to_s] = error
281
+ end
282
+ t.ensure do
283
+ @data_converter = new_options.data_converter
284
+ result = @data_converter.load open_request.result
285
+ output.set(result)
286
+ raise @failure_map[decision_id.to_s] if @failure_map[decision_id.to_s] && new_options.return_on_start
287
+ end
288
+ end
289
+ return output if new_options.return_on_start
290
+ output.get
291
+ this_failure = @failure_map[decision_id.to_s]
292
+ raise this_failure if this_failure
293
+ return output.get
294
+ end
295
+ end
296
+
297
+ # Represents an activity client.
298
+ class ActivityClient < Module
299
+ # Gets the data converter for the Activity Client.
300
+ def data_converter
301
+ @generic_client.data_converter
302
+ end
303
+
304
+ # Sets the data converter for the Activity Client.
305
+ def data_converter=(other)
306
+ @generic_client.data_converter = other
307
+ end
308
+
309
+ # Exponentially retries the supplied method with optional settings.
310
+ #
311
+ # @param [String] method_name The method name to retry.
312
+ #
313
+ # @param [ExponentialRetryOptions] block A hash of ExponentialRetryOptions to use.
314
+ #
315
+ def exponential_retry(method_name, &block)
316
+ @generic_client.retry(method_name, lambda {|first, time_of_failure, attempts| 1}, block)
317
+ end
318
+ end
319
+
320
+ # Methods and constants related to activities.
321
+ #
322
+ # @!attribute activity_client
323
+ # Gets the [ActivityClient] for this Activity.
324
+ #
325
+ # @!attribute activities
326
+ # Gets an list of activities for this Activity.
327
+ #
328
+ module Activities
329
+ @precursors ||= []
330
+ attr_accessor :activity_client, :activities
331
+ def self.extended(base)
332
+ base.send :include, InstanceMethods
333
+ end
334
+ module InstanceMethods
335
+ attr_writer :_activity_execution_context
336
+ def activity_execution_context
337
+ raise IllegalStateException.new("No activity execution context") unless @_activity_execution_context
338
+ @_activity_execution_context
339
+ end
340
+ def record_activity_heartbeat(details)
341
+ @_activity_execution_context.record_activity_heartbeat(details)
342
+ end
343
+ end
344
+
345
+
346
+ # @!visibility private
347
+ extend Utilities::UpwardLookups
348
+
349
+ # @!visibility private
350
+ def look_upwards(variable)
351
+ precursors = self.ancestors.dup
352
+ precursors.delete(self)
353
+ results = precursors.map { |x| x.send(variable) if x.methods.map(&:to_sym).include? variable }.compact.flatten.uniq
354
+ end
355
+ property(:activities, [])
356
+
357
+ # @!visibility private
358
+ def _options; @activities.map(&:options); end
359
+
360
+ # Defines one or more activities, with {ActivityOptions} provided in the supplied block.
361
+ #
362
+ # @param [Array] activity_names
363
+ # The names of the activities to define.
364
+ #
365
+ # @param [Hash] block
366
+ # {ActivityOptions} to use on the defined activities.
367
+ #
368
+ # @example Defining an activity
369
+ # new_activity_class = Class.new(MyActivity) do
370
+ # extend Activities
371
+ # activity :run_activity1 do
372
+ # {
373
+ # :default_task_heartbeat_timeout => "3600",
374
+ # :default_task_list => task_list,
375
+ # :default_task_schedule_to_close_timeout => "20",
376
+ # :default_task_schedule_to_start_timeout => "20",
377
+ # :default_task_start_to_close_timeout => "20",
378
+ # :version => "1",
379
+ # :prefix_name => "#{class_name}Activity"
380
+ # }
381
+ # end
382
+ # def run_activity1
383
+ # end
384
+ # end
385
+ def activity(*activity_names, &block)
386
+ options = Utilities::interpret_block_for_options(ActivityOptions, block)
387
+ activity_names.each do |activity_name|
388
+ prefix_name = options.prefix_name || self.to_s
389
+ activity_type = ActivityType.new(prefix_name + "." + activity_name.to_s, options.version, options)
390
+ @activities ||= []
391
+ @activities << activity_type
392
+ end
393
+ end
394
+ end
395
+
396
+ # This module is for internal use only and may be changed or removed
397
+ # without prior notice. Use {Activities} instead.
398
+ # @!visibility private
399
+ module Activity
400
+ include Activities
401
+ def self.extended(base)
402
+ base.send :include, InstanceMethods
403
+ end
404
+ end
405
+
406
+
407
+ end
408
+ end