lib/async/task.rb in async-2.19.0 vs lib/async/task.rb in async-2.20.0
- old
+ new
@@ -38,21 +38,21 @@
end
end
end
# Raised if a timeout occurs on a specific Fiber. Handled gracefully by `Task`.
- # @public Since `stable-v1`.
+ # @public Since *Async v1*.
class TimeoutError < StandardError
# Create a new timeout error.
#
# @parameter message [String] The error message.
def initialize(message = "execution expired")
super
end
end
- # @public Since `stable-v1`.
+ # @public Since *Async v1*.
class Task < Node
# Raised when a child task is created within a task that has finished execution.
class FinishedError < RuntimeError
# Create a new finished error.
#
@@ -196,11 +196,11 @@
schedule do
@block.call(self, *arguments)
rescue => error
# I'm not completely happy with this overhead, but the alternative is to not log anything which makes debugging extremely difficult. Maybe we can introduce a debug wrapper which adds extra logging.
if @finished.nil?
- Console.warn(self, "Task may have ended with unhandled exception.", exception: error)
+ warn(self, "Task may have ended with unhandled exception.", exception: error)
end
raise
end
else
@@ -208,17 +208,28 @@
end
end
# Run an asynchronous task as a child of the current task.
#
+ # @public Since *Async v1*.
+ # @asynchronous May context switch immediately to the new task.
+ #
+ # @yields {|task| ...} in the context of the new task.
# @raises [FinishedError] If the task has already finished.
# @returns [Task] The child task.
def async(*arguments, **options, &block)
raise FinishedError if self.finished?
task = Task.new(self, **options, &block)
+ # When calling an async block, we deterministically execute it until the first blocking operation. We don't *have* to do this - we could schedule it for later execution, but it's useful to:
+ #
+ # - Fail at the point of the method call where possible.
+ # - Execute determinstically where possible.
+ # - Avoid scheduler overhead if no blocking operation is performed.
+ #
+ # There are different strategies (greedy vs non-greedy). We are currently using a greedy strategy.
task.run(*arguments)
return task
end
@@ -300,11 +311,11 @@
# You can nest calls to defer_stop, but the stop will only be deferred until the outermost block exits.
#
# If stop is invoked a second time, it will be immediately executed.
#
# @yields {} The block of code to execute.
- # @public Since `stable-v1`.
+ # @public Since *Async v1*.
def defer_stop
# Tri-state variable for controlling stop:
# - nil: defer_stop has not been called.
# - false: defer_stop has been called and we are not stopping.
# - true: defer_stop has been called and we will stop when exiting the block.
@@ -357,9 +368,13 @@
def current?
Fiber.current.equal?(@fiber)
end
private
+
+ def warn(...)
+ Console.warn(...)
+ end
# Finish the current task, moving any children to the parent.
def finish!
# Don't hold references to the fiber or block after the task has finished:
@fiber = nil