async
async copied to clipboard
Task hangs during stop if there are more than two sub tasks (?)
I'm on Ruby 3.1.1 and Async 2.0.1, Ubuntu 20.04. The following script hangs after the first Ctrl+C, but only if both sleeping tasks are active:
#!/usr/bin/env ruby
require 'async'
class Server
def initialize
@running = false
end
def stopping?
!@running
end
def stop(&after_shutdown)
@after_shutdown = after_shutdown if after_shutdown
@running = false
end
def start(task: Async::Task.current)
task.async do |task|
@running = true
while @running
run_once
sleep 0.1
end
@after_shutdown.call if @after_shutdown
end
end
def run_once
print '.'
end
end
Async do |task|
server = Server.new
Signal.trap(:INT) do
puts "Got INT"
abort 'Aborting' if server.stopping? # abort on second ^C
server.stop do
puts "Server shut down. Stopping task."
task.stop
end
end
server.start
task.async do
puts "sleeping #1"
sleep
end
# NOTE: Hangs only if this second task is added
task.async do
puts "sleeping #2"
sleep
end
end
puts 'Done'
Maybe related to #137 but it also hangs with all puts commented out.
Thanks, I'll check it.
I was hoping this was fixed together with #137 but it's still happening with Ruby 3.2-preview2:
$ ruby -v
ruby 3.2.0preview2 (2022-09-09 master 35cfc9a3bb) [x86_64-linux]
$ bundle exec ./async_test.rb
Could not load native event selector: cannot load such file -- IO_Event
.sleeping #1
sleeping #2
.....................^CGot INT
Server shut down. Stopping task.
^CGot INT
Aborting
The process should terminate after the first ˆC, but hangs instead. The second one calls Kernel#abort.
My Gemfile (repos checked out at current master/main):
gem 'async', path: '../async'
gem 'io-event', path: '../io-event'
gem 'timers', path: '../timers'
Thanks for the update, I'll investigate.
I could reproduce the issue. I'll investigate more.
Signal.trap behaves strangely in an asynchronous context. We might be able to make it more robust, but we've got a specific construct to handle it - Async::IO::Trap. Let me review this code a bit more and see if there is a better more straight forward solution.
Any updates?
For some odd reason, I could not reproduce the issue any more. Do you mind checking?
I'm sure it's something wrong on my end, I have a local branch with some work to deal with this, but have not pushed it yet.
@ioquatix Yes, it's still happening with v2.5.1 on Ruby 3.2.2:
$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
$ ruby async_bug.rb
2.5.1
.sleeping #1
sleeping #2
...............^CGot INT
Server shut down. Stopping task.
^CGot INT
Aborting
Okay great, thanks, I'll check what's going on.
Here is a smaller repro:
#!/usr/bin/env ruby
require_relative 'lib/async'
Async(annotation: "Top") do |task|
task.async(annotation: "Stopper") do
sleep 0.1
puts "Stopping parent..."
task.stop
end
task.async(annotation: "Sleeper #1") do
puts "sleeping #1"
sleep
end
# NOTE: Hangs only if this second task is added
task.async(annotation: "Sleeper #2") do
puts "sleeping #2"
sleep
end
end
puts 'Done'
I understand the problem and am working on a fix.
@ioquatix Thank you for the fix.