Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure transient tasks are correctly terminated. #245

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/async/scheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def scheduler_close
def close
# It's critical to stop all tasks. Otherwise they might be holding on to resources which are never closed/released correctly.
until self.terminate
self.run_once
self.run_once!
end

Kernel.raise "Closing scheduler with blocked operations!" if @blocked > 0
Expand Down Expand Up @@ -215,6 +215,16 @@ def run_once(timeout = nil)
return false
end

return run_once!(timeout)
end

# Run one iteration of the event loop.
#
# When terminating the event loop, we already know we are finished. So we don't need to check the task tree. This is a logical requirement because `run_once` ignores transient tasks. For example, a single top level transient task is not enough to keep the reactor running, but during termination we must still process it in order to terminate child tasks.
#
# @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite.
# @returns [Boolean] Whether there is more work to do.
private def run_once!(timeout = 0)
interval = @timers.wait_interval

# If there is no interval to wait (thus no timers), and no tasks, we could be done:
Expand Down
13 changes: 13 additions & 0 deletions test/async/reactor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,20 @@
sleep
end

expect(reactor.run_once).to be == false
expect(reactor).to be(:finished?)
reactor.close
end

it "terminates transient tasks with nested tasks" do
task = reactor.async(transient: true) do |parent|
parent.async do |child|
sleep(1)
end
end

reactor.run_once
expect(reactor).to be(:finished?)
reactor.close
end

Expand Down