Class: AWS::Flow::Core::BeginRescueEnsure

Inherits:
FlowFiber
  • Object
show all
Extended by:
SimpleDFA
Defined in:
lib/aws/flow/begin_rescue_ensure.rb

Overview

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.

Direct Known Subclasses

DaemonBeginRescueEnsure

Instance Attribute Summary collapse

Attributes included from SimpleDFA

#start_state, #states, #symbols, #transitions

Instance Method Summary collapse

Methods included from SimpleDFA

add_transition, define_general, get_start_state, get_transitions, init, uncovered_transitions

Methods inherited from FlowFiber

#[], [], []=, #[]=, finalize, unset

Constructor Details

#initialize(options = {}) ⇒ BeginRescueEnsure

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Create a new ‘BeginRescueEnsure` object, with the provided options.

Parameters:

  • options (defaults to: {})

    Options to set for the class.

Options Hash (options):

  • :parent (Object)

    The parent object.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 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

Instance Attribute Details

#__context__Object (readonly)

Returns the value of attribute __context__.



31
32
33
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 31

def __context__
  @__context__
end

#backtraceObject (readonly)

Returns the value of attribute backtrace.



31
32
33
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 31

def backtrace
  @backtrace
end

#begin_taskObject

Returns the value of attribute begin_task.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def begin_task
  @begin_task
end

#cancelledObject

Returns the value of attribute cancelled.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def cancelled
  @cancelled
end

#ensure_taskObject

Returns the value of attribute ensure_task.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def ensure_task
  @ensure_task
end

#executorObject

Returns the value of attribute executor.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def executor
  @executor
end

#failureObject

Returns the value of attribute failure.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def failure
  @failure
end

#heirsObject

Returns the value of attribute heirs.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def heirs
  @heirs
end

#nonDaemonHeirsCountObject

Returns the value of attribute nonDaemonHeirsCount.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def nonDaemonHeirsCount
  @nonDaemonHeirsCount
end

#parentObject

Returns the value of attribute parent.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def parent
  @parent
end

#rescue_hashObject

Returns the value of attribute rescue_hash.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def rescue_hash
  @rescue_hash
end

#resultObject

Returns the value of attribute result.



29
30
31
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 29

def result
  @result
end

Instance Method Details

#<<(async_task) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 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

#alive?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


185
186
187
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 185

def alive?
  @current_state != :closed
end

#begin(block) ⇒ Object

Binds the block to a lambda to be called when we get to the begin part of the data flow analysis.

Parameters:

  • block

    The code block to be called when asynchronous begin starts.



268
269
270
271
272
# 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

#cancel(error) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# 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

#cancelHeirsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



135
136
137
138
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 135

def cancelHeirs
  toCancel = @heirs.dup
  toCancel.each { |heir|  heir.cancel(@failure) }
end

#check_closedObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



92
93
94
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 92

def check_closed
  raise IllegalStateException, @failure if @current_state == :closed
end

#ensure(block) ⇒ Object

Binds the block to a lambda to be called when we get to the ensure part of the data flow analysis.

Parameters:

  • block

    The code block to be called when asynchronous ensure starts.



296
297
298
299
# 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

#fail(this_task, error) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Fails the task, cancels all of its heirs, and then updates the state.

Parameters:

  • this_task

    The task to fail.

  • error

    The error associated with the failure.



105
106
107
108
109
110
111
112
113
114
115
116
117
# 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

#get_closest_containing_scopeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



84
85
86
87
88
89
# 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

#get_heirsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



206
207
208
209
210
211
212
213
# 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

#is_daemon?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


62
63
64
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 62

def is_daemon?
  false
end

#merge_stacktraces(failure, this_backtrace, error) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



141
142
143
144
# 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

#remove(this_task) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Removes the task and updates the state.

Parameters:

  • this_task

    The task to remove.



125
126
127
128
129
130
131
132
# 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

#rescue(error_types, block) ⇒ Object

Binds the block to a lambda to be called when we get to the rescue part of the DFA

Parameters:

  • error_types

    The error types.

  • block

    The code block to be called when asynchronous rescue starts.



282
283
284
285
286
287
288
289
# 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

#runObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Actually runs the BeginRescueEnsure, by going through the data flow analysis with the symbol :run.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# 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

#scheduleObject



301
302
303
# File 'lib/aws/flow/begin_rescue_ensure.rb', line 301

def schedule
  @parent << self
end

#update_stateObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Updates the state based on the most recent transitions in the data flow analysis.



191
192
193
194
195
196
197
198
199
200
201
202
203
# 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