lib/async/task.rb in async-2.2.1 vs lib/async/task.rb in async-2.3.0
- old
+ new
@@ -109,38 +109,43 @@
else
raise RuntimeError, "Task already running!"
end
end
+ # Run an asynchronous task as a child of the current task.
def async(*arguments, **options, &block)
+ raise "Cannot create child task within a task that has finished execution!" if self.finished?
+
task = Task.new(self, **options, &block)
task.run(*arguments)
return task
end
- # Retrieve the current result of the task. Will cause the caller to wait until result is available.
- # @raises[RuntimeError] If the task's fiber is the current fiber.
+ # Retrieve the current result of the task. Will cause the caller to wait until result is available. If the result was an exception, raise that exception.
+ #
+ # Conceptually speaking, waiting on a task should return a result, and if it throws an exception, this is certainly an exceptional case that should represent a failure in your program, not an expected outcome. In other words, you should not design your programs to expect exceptions from `#wait` as a normal flow control, and prefer to catch known exceptions within the task itself and return a result that captures the intention of the failure, e.g. a `TimeoutError` might simply return `nil` or `false` to indicate that the operation did not generate a valid result (as a timeout was an expected outcome of the internal operation in this case).
+ #
+ # @raises [RuntimeError] If the task's fiber is the current fiber.
# @returns [Object] The final expression/result of the task's block.
def wait
- raise "Cannot wait on own fiber" if Fiber.current.equal?(@fiber)
+ raise "Cannot wait on own fiber!" if Fiber.current.equal?(@fiber)
if running?
@finished ||= Condition.new
@finished.wait
end
- case @result
- when Exception
+ if @result.is_a?(Exception)
raise @result
else
return @result
end
end
- # Access the result of the task without waiting. May be nil if the task is not completed.
+ # Access the result of the task without waiting. May be nil if the task is not completed. Does not raise exceptions.
attr :result
# Stop the task and all of its children.
def stop(later = false)
if self.stopped?
@@ -266,10 +271,10 @@
# Attempt to remove this node from the task tree.
consume
# If this task was being used as a future, signal completion here:
if @finished
- @finished.signal(@result)
+ @finished.signal(self)
end
end
# Set the current fiber's `:async_task` to this task.
def set!