lib/async/task.rb in async-1.19.0 vs lib/async/task.rb in async-1.20.0

- old
+ new

@@ -132,17 +132,24 @@ # Soon to become attr :result # Stop the task and all of its children. # @return [void] def stop - @children&.each(&:stop) - - if self.current? - raise Stop, "Stopping current fiber!" - elsif @fiber.alive? - @fiber.resume(Stop.new) + if self.stopping? + # If we are already stopping this task... don't try to stop it again. + return true + elsif self.running? + @status = :stopping + + if self.current? + raise Stop, "Stopping current fiber!" + elsif @fiber.alive? + @fiber.resume(Stop.new) + end end + ensure + @children&.each(&:stop) end # Lookup the {Task} for the current fiber. Raise `RuntimeError` if none is available. # @return [Async::Task] # @raise [RuntimeError] if task was not {set!} for the current fiber. @@ -174,11 +181,19 @@ def failed? @status == :failed end + def stopping? + @status == :stopping + end + def stopped? @status == :stopped + end + + def complete? + @status == :complete end private # This is a very tricky aspect of tasks to get right. I've modelled it after `Thread` but it's slightly different in that the exception can propagate back up through the reactor. If the user writes code which raises an exception, that exception should always be visible, i.e. cause a failure. If it's not visible, such code fails silently and can be very difficult to debug.