aws-flow 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/aws-flow.gemspec +4 -2
  2. data/lib/aws-flow.rb +1 -0
  3. data/lib/aws/decider/decider.rb +2 -2
  4. data/lib/aws/decider/workflow_client.rb +1 -0
  5. data/lib/aws/decider/workflow_clock.rb +3 -3
  6. metadata +3 -29
  7. data/aws-flow-core/Gemfile +0 -9
  8. data/aws-flow-core/LICENSE.TXT +0 -15
  9. data/aws-flow-core/NOTICE.TXT +0 -14
  10. data/aws-flow-core/Rakefile +0 -27
  11. data/aws-flow-core/aws-flow-core.gemspec +0 -12
  12. data/aws-flow-core/lib/aws/flow.rb +0 -26
  13. data/aws-flow-core/lib/aws/flow/async_backtrace.rb +0 -134
  14. data/aws-flow-core/lib/aws/flow/async_scope.rb +0 -195
  15. data/aws-flow-core/lib/aws/flow/begin_rescue_ensure.rb +0 -386
  16. data/aws-flow-core/lib/aws/flow/fiber.rb +0 -77
  17. data/aws-flow-core/lib/aws/flow/flow_utils.rb +0 -50
  18. data/aws-flow-core/lib/aws/flow/future.rb +0 -109
  19. data/aws-flow-core/lib/aws/flow/implementation.rb +0 -151
  20. data/aws-flow-core/lib/aws/flow/simple_dfa.rb +0 -85
  21. data/aws-flow-core/lib/aws/flow/tasks.rb +0 -405
  22. data/aws-flow-core/test/aws/async_backtrace_spec.rb +0 -41
  23. data/aws-flow-core/test/aws/async_scope_spec.rb +0 -118
  24. data/aws-flow-core/test/aws/begin_rescue_ensure_spec.rb +0 -665
  25. data/aws-flow-core/test/aws/external_task_spec.rb +0 -197
  26. data/aws-flow-core/test/aws/factories.rb +0 -52
  27. data/aws-flow-core/test/aws/fiber_condition_variable_spec.rb +0 -163
  28. data/aws-flow-core/test/aws/fiber_spec.rb +0 -78
  29. data/aws-flow-core/test/aws/flow_spec.rb +0 -255
  30. data/aws-flow-core/test/aws/future_spec.rb +0 -210
  31. data/aws-flow-core/test/aws/rubyflow.rb +0 -22
  32. data/aws-flow-core/test/aws/simple_dfa_spec.rb +0 -63
  33. data/aws-flow-core/test/aws/spec_helper.rb +0 -36
@@ -1,50 +0,0 @@
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
- # This file simply contains definitions and functions useful to the overall running of flow
17
- module AWS
18
- module Flow
19
- module Core
20
- class IllegalStateException < Exception; end
21
- class CancellationException < Exception
22
- attr_accessor :reason, :details
23
- def initialize(reason = nil, details = nil)
24
- @reason = reason
25
- @details = details
26
- end
27
- end
28
-
29
- def make_backtrace(parent_backtrace)
30
- # 1 frame for the function that actually removes the stack traces
31
- # 1 frame for the function that calls into the function that removes
32
- # frames in AsyncBacktrace
33
- # 1 frame for the call into this function
34
- # 1 frame for the initialize call of the BRE or External Task
35
- # 1 frame for the new call into the BRE or ET
36
- # 1 frame for the AsyncScope initialize that the BRE/ET has to be in
37
-
38
- # "./lib/aws/rubyflow/asyncBacktrace.rb:75:in `caller'"
39
- # "./lib/aws/rubyflow/asyncBacktrace.rb:21:in `create'"
40
- # "./lib/aws/rubyflow/flow.rb:16:in `make_backtrace'"
41
- # "./lib/aws/rubyflow/flow.rb:103:in `initialize'"
42
- # "./lib/aws/rubyflow/asyncScope.rb:17:in `new'"
43
- # "./lib/aws/rubyflow/asyncScope.rb:17:in `initialize'"
44
-
45
- frames_to_skip = 7
46
- backtrace = AsyncBacktrace.create(parent_backtrace, frames_to_skip)
47
- end
48
- end
49
- end
50
- end
@@ -1,109 +0,0 @@
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
- # This file contains our Future implementation, which allows us to have asynchronous, blocking promises
17
-
18
- module AWS
19
- module Flow
20
- module Core
21
- class AlreadySetException < Exception; end
22
-
23
- # A Future represents the result of an asynchronous computation. Methods are
24
- # provided to check if the computation is complete(Future#set), to wait for
25
- # its completion(Future#wait), and to retrieve the result of the
26
- # computation(Future#get). The result can only be retrieved using method get
27
- # when the computation has completed, blocking if necessary until it is
28
- # ready. This is okay, however, because it will block that Fiber, and
29
- # another Fiber will start executing
30
- class Future
31
-
32
- # Sets the value of the future, and notifies all of the Fibers that tried
33
- # to get when this future wasn't ready.
34
- def set(result=nil)
35
- raise AlreadySetException if @set
36
- @set = true
37
- @result = result
38
- @conditional.broadcast if @conditional
39
- @listeners.each { |b| b.call(self) } if @listeners
40
- self
41
- end
42
-
43
- # Blocks if Future is not set
44
- # raises CancellationError when task is cancelled
45
- def get
46
- until @set
47
- @conditional ||= FiberConditionVariable.new
48
- @conditional.wait
49
- end
50
- @result
51
- end
52
-
53
- def set?
54
- @set
55
- end
56
-
57
- def unset
58
- @set = nil
59
- @result = nil
60
- end
61
-
62
- # Add a callback, block, which will fire when the future is set
63
- def on_set(&block)
64
- @listeners ||= []
65
- # TODO probably want to use lambda here
66
- @listeners << block
67
- end
68
- end
69
-
70
- # Based on the ruby core source:
71
- # https://github.com/ruby/ruby/blob/trunk/lib/thread.rb
72
- class FiberConditionVariable
73
- #
74
- # Creates a new ConditionVariable
75
- #
76
- def initialize
77
- @waiters = []
78
- end
79
-
80
-
81
- # Have the current fiber wait on this condition variable, and wake up when
82
- # the FiberConditionVariable is signalled/broadcaster
83
- def wait
84
- fiber = ::Fiber.current
85
- @waiters << fiber
86
- Fiber.yield
87
- self
88
- end
89
-
90
- #
91
- # Wakes up the first fiber in line waiting for this lock.
92
- #
93
- def signal
94
- t = @waiters.shift
95
- t.schedule if t && t.alive?
96
- self
97
- end
98
-
99
- #
100
- # Wakes up all fibers waiting for this lock.
101
- #
102
- def broadcast
103
- signal until @waiters.empty?
104
- self
105
- end
106
- end
107
- end
108
- end
109
- end
@@ -1,151 +0,0 @@
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
- # This file contains the externally visible parts of flow that are expected to be used by customers of flow
17
- module AWS
18
- module Flow
19
- module Core
20
- class NoContextException < Exception; end
21
-
22
- # @param block
23
- # The block of code to be executed when the task is run.
24
- #
25
- # @raise [NoContextException]
26
- # If the current fiber does not respond to {#__context__}.
27
- #
28
- # @return [Future]
29
- # The tasks result, which is a {Future}.
30
- #
31
- def task(future = nil, &block)
32
- fiber = ::Fiber.current
33
- raise NoContextException unless fiber.respond_to? :__context__
34
- context = fiber.__context__
35
- t = Task.new(nil, &block)
36
- task_context = TaskContext.new(:parent => context.get_closest_containing_scope, :task => t)
37
- context << t
38
- t.result
39
- end
40
-
41
- #
42
- # @param block
43
- # The block of code to be executed when the daemon task is run.
44
- #
45
- # @return [Future]
46
- # The tasks result, which is a {Future}.
47
- #
48
- # @raise [NoContextException]
49
- # If the current fiber does not respond to {#__context__}.
50
- #
51
- def daemon_task(&block)
52
- fiber = ::Fiber.current
53
- raise NoContextException unless fiber.respond_to? :__context__
54
- context = fiber.__context__
55
- t = DaemonTask.new(nil, &block)
56
- task_context = TaskContext.new(:parent => context.get_closest_containing_scope, :task => t)
57
- context << t
58
- t.result
59
- end
60
-
61
- #
62
- # @param block
63
- # The block of code to be executed when the external task is run.
64
- #
65
- # @return [nil]
66
- #
67
- # @raise [NoContextException]
68
- # If the current fiber does not respond to {#__context__}.
69
- #
70
- def external_task(&block)
71
- fiber = ::Fiber.current
72
- raise NoContextException unless fiber.respond_to? :__context__
73
- context = fiber.__context__
74
- t = ExternalTask.new(:parent => context.get_closest_containing_scope, &block)
75
- task_context = TaskContext.new(:parent => context.get_closest_containing_scope, :task => t)
76
- context << t
77
- nil
78
- end
79
-
80
-
81
- #
82
- #
83
- # * *Args* :
84
- # - block -> a block, which is passed in a BeginRescueEnsureWrapper, and which will define the BeginRescueEnsure#begin, BeginRescueEnsure#rescue, and BeginRescueEnsure#ensure methods
85
- # * *Returns* :
86
- # - The result of the begin statement, if there is no error, otherwise the value of the return statement
87
- # * *Raises* :
88
- # - +NoContextException+ -> If the current fiber does not respond to #__context__
89
- #
90
- def error_handler(&block)
91
- fiber = ::Fiber.current
92
- raise NoContextException unless fiber.respond_to? :__context__
93
- context = fiber.__context__
94
- begin_rescue_ensure = BeginRescueEnsure.new(:parent => context.get_closest_containing_scope)
95
- bge = BeginRescueEnsureWrapper.new(block, begin_rescue_ensure)
96
- context << bge
97
- context << begin_rescue_ensure
98
- begin_rescue_ensure
99
- end
100
-
101
- # @param block
102
- # A code block, which is passed within a {BeginRescueEnsureWrapper}, and which must define the
103
- # {BeginRescueEnsure#begin}, {BeginRescueEnsure#rescue}, and {BeginRescueEnsure#ensure} methods.
104
- # @!visibility private
105
- def _error_handler(&block)
106
- error_handler(&block).result
107
- end
108
-
109
-
110
- def wait_for_function(function, *futures)
111
- conditional = FiberConditionVariable.new
112
- futures.flatten!
113
- return nil if futures.empty?
114
- result = futures.select(&:set?)
115
- return futures.find(&:set?)if function.call(result, futures)
116
- futures.each do |f|
117
- f.on_set do |set_one|
118
- result << set_one
119
- conditional.broadcast if function.call(result, futures)
120
- end
121
- end
122
- conditional.wait
123
- result
124
- end
125
-
126
- # Blocks until *any* of the arguments are set.
127
- #
128
- # @param [Array] futures
129
- # A list of futures to wait for. The function will return when at least one of these is set.
130
- #
131
- # @return [Array]
132
- # A list of the set futures, in the order of being set.
133
- #
134
- def wait_for_any(*futures)
135
- wait_for_function(lambda {|result, future_list| result.length >= 1 }, futures)
136
- end
137
-
138
- # Blocks until *all* of the arguments are set.
139
- #
140
- # @param [Array<Future>] futures
141
- # A list of futures to wait for. The function will return only when all of them are set.
142
- #
143
- # @return [Array]
144
- # A list of the set futures, in the order of being set.
145
- #
146
- def wait_for_all(*futures)
147
- wait_for_function(lambda {|result, future_list| result.size == future_list.size}, futures)
148
- end
149
- end
150
- end
151
- end
@@ -1,85 +0,0 @@
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
- module Core
19
-
20
- # Contains a Data Flow Analysis (DFA)-like framework, where transition functions can perform arbitrary computation
21
- # before moving to the next state
22
- module SimpleDFA
23
- attr_accessor :transitions, :symbols, :states, :start_state
24
-
25
- # Creates a new SimpleDFA instance.
26
- #
27
- # @param start_state
28
- # The state with which to start the framework.
29
- #
30
- def init(start_state)
31
- include InstanceMethods
32
- @start_state = start_state
33
- @symbols = []
34
- @states = []
35
- @transitions = {}
36
- @states << start_state
37
- end
38
-
39
- # @return the start state
40
- # The start state that was provided when this instance was created.
41
- #
42
- def get_start_state
43
- @start_state
44
- end
45
-
46
- # @return [Array]
47
- # The list of all transitions that were added with {#add_transition}.
48
- #
49
- def get_transitions
50
- @transitions
51
- end
52
-
53
- def define_general(state, &block)
54
- @symbols.each do |symbol|
55
- if @transitions[[state, symbol]].nil?
56
- @transitions[[state, symbol]] = block
57
- end
58
- end
59
- end
60
-
61
- def add_transition(state, symbol, &block)
62
- @symbols << symbol unless @symbols.include? symbol
63
- @states << state unless @states.include? state
64
- @transitions[[state, symbol]] = block
65
- end
66
-
67
- def uncovered_transitions
68
- @states.product(@symbols) - @transitions.keys
69
- end
70
-
71
- module InstanceMethods
72
- attr_accessor :current_state
73
-
74
- def consume(symbol)
75
- @current_state ||= self.class.get_start_state
76
- func_to_call = self.class.get_transitions[[@current_state, symbol]]
77
- raise "This is not a legal transition" unless func_to_call
78
- func_to_call.call(self)
79
- end
80
- end
81
- end
82
-
83
- end
84
- end
85
- end
@@ -1,405 +0,0 @@
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
- # Contains all the task methods, which allow arbitrary blocks of code to be run asynchronously
17
-
18
- module AWS
19
- module Flow
20
- module Core
21
- class Task < FlowFiber
22
- attr_reader :result, :block
23
- attr_accessor :backtrace, :__context__, :parent
24
-
25
- # Creates a new Task.
26
- #
27
- # @param __context__
28
- # A Task needs a reference to the __context__ that created it so that when the "task" macro is called it can
29
- # find the __context__ which the new Task should be added to.
30
- #
31
- # @param block
32
- # A block of code that will be run by the task.
33
- #
34
- def initialize(__context__, &block)
35
- @__context__ = __context__
36
- @result = Future.new
37
- @block = block
38
-
39
- # Is the task alive?
40
- def alive?
41
- super && !@cancelled
42
- #!!@alive# && !@cancelled
43
- end
44
-
45
- # @return
46
- # The executor for this task.
47
- def executor
48
- @__context__.executor
49
- end
50
-
51
- super() do
52
- begin
53
- # Not return because 1.9 will freak about local jump problems if you
54
- # try to return, as this is inside a block
55
- next if @cancelled
56
- @result.set(lambda(&block).call)
57
- next if @cancelled
58
- @__context__.remove(self)
59
- rescue Exception => e
60
- if @backtrace != e
61
- backtrace = AsyncBacktrace.create_from_exception(@backtrace, e)
62
- e.set_backtrace(backtrace.backtrace) if backtrace
63
- end
64
- @__context__.fail(self, e)
65
- ensure
66
- end
67
- end
68
- end
69
-
70
- #
71
- # Passes the get_heirs calls to the context, to ensure uniform handling of get_heirs
72
- #
73
- def get_heirs
74
- @__context__.get_heirs
75
- end
76
-
77
- #
78
- # Returns true/false, depending on if we are in a daemon task or not
79
- #
80
- def is_daemon?
81
- return false
82
- end
83
-
84
- # Used by Future#signal to schedule the task for re-evaluation.
85
- #
86
- # This will simply add the task back to the list of things to be run in the parent's event loop.
87
- #
88
- def schedule
89
- @__context__ << self
90
- end
91
-
92
- # Cancel will prevent the execution of this particular task, if possible
93
- #
94
- # @param error
95
- # The error that is the cause of the cancellation
96
- #
97
- def cancel(error)
98
- @cancelled = true
99
- @__context__.remove(self)
100
- end
101
-
102
- # Fails the given task with the specified error.
103
- #
104
- # @param error
105
- # The error that is the cause of the cancellation
106
- #
107
- # @!visibility private
108
- def fail(this_task, error)
109
- @__context__.fail(this_task, error)
110
- end
111
- # def fail(this_task, error)
112
- # raise error
113
- # end
114
-
115
- # Adds a task to this task's context
116
- #
117
- # @param this_task
118
- # The task to add.
119
- #
120
- def <<(this_task)
121
- @__context__.parent << this_task
122
- end
123
-
124
- # Removes a task from this task's context
125
- #
126
- # @param this_task
127
- # The task to remove.
128
- #
129
- def remove(this_task)
130
- @__context__.remove(this_task)
131
- end
132
-
133
-
134
- end
135
-
136
-
137
- # Similar to a regular Task in all functioning except that it is not assured a chance to execute. Whereas a
138
- # begin/run/execute block cannot be closed out while there are still nonDaemonHeirs, it can happily entered the
139
- # closed state with daemon heirs, making them essentially unrunnable.
140
- class DaemonTask < Task
141
-
142
- def is_daemon?
143
- return true
144
- end
145
-
146
- end
147
-
148
- # External Tasks are used to bridge asynchronous execution to external asynchronous APIs or events. It is passed a block, like so
149
- #
150
- # external_task do |t|
151
- # t.cancellation_handler { |h, cause| h.fail(cause) }
152
- # t.initiate_task { |h| trace << :task_started; h.complete; }
153
- # end
154
- #
155
- # The {ExternalTask#initiate_task} method is expected to call an external API and return without blocking.
156
- # Completion or failure of the external task is reported through ExternalTaskCompletionHandle, which is passed into
157
- # the initiate_task and cancellation_handler blocks. The cancellation handler, defined in the same block as the
158
- # initiate_task, is used to report the cancellation of the external task.
159
- #
160
- class ExternalTask < FlowFiber
161
- attr_reader :block
162
- attr_accessor :cancelled, :inCancellationHandler, :parent, :backtrace, :__context__
163
-
164
-
165
- # Will always be false, provides a common api for BRE's to ensure they are maintaining their nonDaemonHeirsCount
166
- # correctly
167
- # @!visibility private
168
- def is_daemon?
169
- false
170
- end
171
-
172
- #
173
- # Passes the get_heirs calls to the context, to ensure uniform handling of
174
- # get_heirs
175
- #
176
- # @!visibility private
177
- def get_heirs
178
- @__context__.get_heirs
179
- end
180
-
181
- # @!visibility private
182
- def initialize(options = {}, &block)
183
- @inCancellationHandler = false
184
- @block = block
185
- # TODO: What should the default value be?
186
- @parent = options[:parent]
187
- @handle = ExternalTaskCompletionHandle.new(self)
188
- block.call(self)
189
- end
190
-
191
- # This method is here because the way we create ExternalTasks is a little
192
- # tricky - if the parent isn't passed in on construction(as is the case with
193
- # the external_task function), then the parent will only be set after
194
- # ExternalTask#initialize is called. We'd prefer to set it in the initiailze,
195
- # however, the backtrace relies on the parent's backtrace, and so we cannot do
196
- # that. Instead, we use this method to lazily create it, when it is
197
- # called. The method itself simply sets the backtrace to the the
198
- # make_backtrace of the parent's backtrace, if the backtrace is not already
199
- # set, and will otherwise simply return the backtrace
200
- # @!visibility private
201
- def backtrace
202
- @backtrace ||= make_backtrace(@parent.backtrace)
203
- end
204
-
205
- # Add a task which removes yourself, and pass it through the parents executor
206
- # @!visibility private
207
- def remove_from_parent
208
- @__context__.executor << FlowFiber.new { @parent.remove(self) }
209
- end
210
-
211
- # Add a task which fails yourself with the suppiled error, and pass it through
212
- # the parents executor
213
- # @!visibility private
214
- def fail_to_parent(error)
215
- @__context__.executor << FlowFiber.new { @parent.fail(self, error) }
216
- end
217
-
218
-
219
- # Part of the interface provided by Fiber, has to overridden to properly
220
- # reflect that an ExternalTasks alive-ness relies on it's
221
- # ExternalTaskCompletionHandle
222
- # @!visibility private
223
- def alive?
224
- ! @handle.completed
225
- end
226
-
227
- # @!visibility private
228
- def cancel(cause)
229
- return if @cancelled
230
- return if @handle.failure != nil || @handle.completed
231
- @cancelled = true
232
- if @cancellation_task != nil
233
- begin
234
- @inCancellationHandler = true
235
- @cancellation_task.call(cause)
236
- rescue Exception => e
237
- if ! self.backtrace.nil?
238
- backtrace = AsyncBacktrace.create_from_exception(@backtrace, e)
239
- e.set_backtrace(backtrace.backtrace) if backtrace
240
- end
241
- @handle.failure = e
242
- ensure
243
- @inCancellationHandler = false
244
- if ! @handle.failure.nil?
245
- fail_to_parent(@handle.failure)
246
- elsif @handle.completed
247
- remove_from_parent
248
- end
249
- end
250
- else
251
- remove_from_parent
252
- end
253
- end
254
-
255
- # Store the cancellation handler block passed in for later reference
256
- # @!visibility private
257
- def cancellation_handler(&block)
258
- @cancellation_task = lambda { |cause| block.call(@handle, cause) }
259
- end
260
-
261
- # Store the block passed in for later
262
- # @!visibility private
263
- def initiate_task(&block)
264
- @initiation_task = lambda { block.call(@handle) }
265
- end
266
-
267
- # From the interface provided by Fiber, will execute the External Task
268
- # @!visibility private
269
- def resume
270
- return if @cancelled
271
- begin
272
- @cancellation_handler = @initiation_task.call
273
- rescue Exception => e
274
- backtrace = AsyncBacktrace.create_from_exception(self.backtrace, e)
275
- e.set_backtrace(backtrace.backtrace) if backtrace
276
- @parent.fail(self, e)
277
- end
278
- end
279
- end
280
-
281
- # Used to complete or fail an external task initiated through
282
- # ExternalTask#initiate_task, and thus handles the logic of what to do when the
283
- # external task is failed.
284
- # @!visibility private
285
- class ExternalTaskCompletionHandle
286
- attr_accessor :completed, :failure, :external_task
287
-
288
- # @!visibility private
289
- def initialize(external_task)
290
- @external_task = external_task
291
- end
292
-
293
- # Will merge the backtrace, set the @failure, and then fail the task from the parent
294
- # @!visibility private
295
- #
296
- # @param error
297
- # The exception to fail on
298
- #
299
- # @raise IllegalStateException
300
- # Raises if failure hasn't been set, or if the task is already completed
301
- #
302
- # @!visibility private
303
- def fail(error)
304
- if ! @failure.nil?
305
- raise IllegalStateException, "Invalid ExternalTaskCompletionHandle"
306
- end
307
- if @completed
308
- raise IllegalStateException, "Already completed"
309
- end
310
- #TODO Might want to flip the logic to only alert if variable is set
311
- if @stacktrace.nil?
312
- if ! @external_task.backtrace.nil?
313
- backtrace = AsyncBacktrace.create_from_exception(@external_task.backtrace, error)
314
- error.set_backtrace(backtrace.backtrace) if backtrace
315
- end
316
- end
317
- @failure = error
318
- if ! @external_task.inCancellationHandler
319
- @external_task.fail_to_parent(error)
320
- end
321
- end
322
-
323
- # Set's the task to complete, and removes it from it's parent
324
- #
325
- # @raise IllegalStateException
326
- # If the failure hasn't been set, or if the task is already completed
327
- #
328
- # @!visibility private
329
- def complete
330
- if ! failure.nil?
331
- raise IllegalStateException, ""
332
- end
333
-
334
- if @completed
335
- raise IllegalStateException, "Already Completed"
336
- end
337
- @completed = true
338
- @external_task.remove_from_parent if ! @external_task.inCancellationHandler
339
- end
340
- end
341
-
342
- # TaskContext is the class that holds some meta-information for tasks, and which stores the parent link for tasks.
343
- # It seperates some of the concerns between tasks and what they have to know to follow back up the chain.
344
- #
345
- # All the methods here will simply delegate calls, either up to the parent, or down to the task
346
- # @!visibility private
347
- class TaskContext
348
-
349
- attr_accessor :daemon, :parent, :backtrace, :cancelled
350
-
351
- def initialize(options = {})
352
- @parent = options[:parent]
353
- @task = options[:task]
354
- @task.__context__ = self
355
- @non_cancelling = options[:non_cancelling]
356
- @daemon = options[:daemon]
357
- end
358
-
359
- # @!visibility private
360
- def get_closest_containing_scope
361
- @task
362
- # @ parent
363
- end
364
-
365
- # @!visibility private
366
- def alive?
367
- @task.alive?
368
- end
369
-
370
- # @!visibility private
371
- def executor
372
- @parent.executor
373
- end
374
-
375
- # @!visibility private
376
- def get_heirs
377
- str = "I am a #{@task.class}
378
- and my block looks like #{@task.block}"
379
- end
380
-
381
- # @!visibility private
382
- def fail(this_task, error)
383
- @parent.fail(this_task, error)
384
- end
385
-
386
- # @!visibility private
387
- def remove(thread)
388
- @parent.remove(thread)
389
- end
390
-
391
- # @!visibility private
392
- def cancel(error_type)
393
- @task.cancelled = true
394
- @parent.cancel(self)
395
- end
396
-
397
- # @!visibility private
398
- def <<(task)
399
- @parent << task
400
- end
401
-
402
- end
403
- end
404
- end
405
- end