class AWS::Flow::Core::BeginRescueEnsure
Enables asynchronous error handling within the AWS
Flow
Framework for Ruby. Calling {#begin}/{#rescue}/{#ensure} is similar to Ruby’s native ‘begin`/`rescue`/`end` semantics.
Attributes
Public Class Methods
Create a new ‘BeginRescueEnsure` object, with the provided options.
@param options
Options to set for the class.
@option options [Object] :parent
The parent object.
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 42 def initialize(options = {}) # We have two different arrays, rather than a hash, # because we want to ensure that we process the rescues in the order # they are written, and because prior to Ruby 1.9, hashes will not # return their elements in the order they were inserted. @rescue_hash = {} @parent = options[:parent] || Fiber.current.__context__ @current = @parent @executor = @parent.executor @__context__ = self @nonDaemonHeirsCount = 0 @current_state ||= self.class.get_start_state @heirs = Set.new @backtrace = make_backtrace(@parent.backtrace) @result = Future.new super() { consume(:run) } end
Public Instance Methods
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 68 def <<(async_task) # Not going to include the promise to wait for, as it would appear that # fibers can wait on futures from their point of origin as part of their # implementation, as opposed to adding the callback here. check_closed if ! @heirs.member? async_task @heirs << async_task if ! async_task.is_daemon? @nonDaemonHeirsCount += 1 end end @executor << async_task self end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 185 def alive? @current_state != :closed end
Binds the block to a lambda to be called when we get to the begin part of the data flow analysis.
@param block
The code block to be called when asynchronous *begin* starts.
# File lib/aws/flow/begin_rescue_ensure.rb, line 268 def begin(block) raise "Duplicated begin" if @begin_task # @begin_task = lambda { block.call } @begin_task = Task.new(self) { @result.set(block.call) } end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 147 def cancel(error) if @current_state == :created @current_state = :closed @parent.remove(self) return end if @failure == nil @cancelled = true details = (error.respond_to? :details) ? error.details : nil reason = (error.respond_to? :reason) ? error.reason : nil @failure = CancellationException.new(reason, details) @failure.set_backtrace(@backtrace.backtrace) if @backtrace if @current_state == :begin cancelHeirs end end end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 135 def cancelHeirs toCancel = @heirs.dup toCancel.each { |heir| heir.cancel(@failure) } end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 92 def check_closed raise IllegalStateException, @failure if @current_state == :closed end
Binds the block to a lambda to be called when we get to the ensure part of the data flow analysis.
@param block
The code block to be called when asynchronous *ensure* starts.
# File lib/aws/flow/begin_rescue_ensure.rb, line 296 def ensure(block) raise "Duplicated ensure" if @ensure_task @ensure_task = Task.new(self) { block.call } end
Fails the task, cancels all of its heirs, and then updates the state.
@param this_task
The task to fail.
@param error
The error associated with the failure.
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 105 def fail(this_task, error) check_closed if ( ! (error.class <= CancellationException) || @failure == nil && !@daemondCausedCancellation) backtrace = AsyncBacktrace.create_from_exception(@backtrace, error) error.set_backtrace(backtrace.backtrace) if backtrace @failure = error end task_out = @heirs.delete?(this_task) raise "There was a task attempted to be removed from a BRE, when the BRE did not have that task as an heir" unless task_out @nonDaemonHeirsCount -= 1 unless this_task.is_daemon? cancelHeirs update_state end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 84 def get_closest_containing_scope # BeginRescueEnsure's are special in that they act as a containing scope, so that things # created in BeginRescueEnsure's treat it as the parent, so that it can track the heirs # correctly and close only when nonDaemonHeirsCount is 0. self end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 206 def get_heirs # TODO fix this so it returns string instead of printing to stdout str = "I am a BeginRescueEnsure with #{heirs.length} heirs my begin block looks like #{@begin_task}" + @heirs.map(&:get_heirs).to_s # (@heirs.each(&:get_heirs) + [self]).flatten end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 62 def is_daemon? false end
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 141 def merge_stacktraces(failure, this_backtrace, error) backtrace = AsyncBacktrace.create_from_exception(this_backtrace, error) failure.set_backtrace(backtrace.backtrace) if backtrace end
Removes the task and updates the state.
@param this_task
The task to remove.
@api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 125 def remove(this_task) check_closed task_out = @heirs.delete?(this_task) raise "There was a task attempted to be removed from a BRE, when the BRE did not have that task as an heir" unless task_out @nonDaemonHeirsCount -= 1 unless this_task.is_daemon? update_state end
Binds the block to a lambda to be called when we get to the rescue part of the DFA
@param error_types
The error types.
@param block
The code block to be called when asynchronous *rescue* starts.
# File lib/aws/flow/begin_rescue_ensure.rb, line 282 def rescue(error_types, block) error_types = [error_types] unless error_types.is_a? Array this_task = lambda { |failure| block.call(failure) } if @rescue_hash.key? error_types raise "You have already registered #{error_types}" end @rescue_hash[error_types] = this_task end
Actually runs the BeginRescueEnsure
, by going through the data flow analysis with the symbol :run. @api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 167 def run this_failure = @failure begin consume(:run) rescue Exception => error if this_failure != error backtrace = AsyncBacktrace.create_from_exception(@backtrace, error) error.set_backtrace(backtrace.backtrace) if backtrace end @failure = error cancelHeirs ensure update_state raise @failure if (!!@failure && @current_state == :closed) end end
# File lib/aws/flow/begin_rescue_ensure.rb, line 301 def schedule @parent << self end
Updates the state based on the most recent transitions in the data flow analysis. @api private
# File lib/aws/flow/begin_rescue_ensure.rb, line 191 def update_state #TODO ? Add the ! @executed part #return if @current_state == :closed || ! @executed return if @current_state == :closed if @nonDaemonHeirsCount == 0 if @heirs.empty? consume(:update_state) else @daemondCausedCancellation = true if @failure == nil cancelHeirs end end end