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

Task hangs during stop if there are more than two sub tasks (?) #158

Closed
paddor opened this issue Mar 17, 2022 · 11 comments · Fixed by #242
Closed

Task hangs during stop if there are more than two sub tasks (?) #158

paddor opened this issue Mar 17, 2022 · 11 comments · Fixed by #242
Assignees
Labels

Comments

@paddor
Copy link
Contributor

paddor commented Mar 17, 2022

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.

@ioquatix
Copy link
Member

Thanks, I'll check it.

@ioquatix ioquatix self-assigned this Mar 17, 2022
@ioquatix ioquatix added the bug label Mar 17, 2022
@paddor
Copy link
Contributor Author

paddor commented Oct 18, 2022

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'

@ioquatix
Copy link
Member

Thanks for the update, I'll investigate.

@ioquatix
Copy link
Member

I could reproduce the issue. I'll investigate more.

@ioquatix
Copy link
Member

ioquatix commented Nov 1, 2022

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.

@paddor
Copy link
Contributor Author

paddor commented Feb 27, 2023

Any updates?

@ioquatix
Copy link
Member

ioquatix commented Jun 6, 2023

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.

@paddor
Copy link
Contributor Author

paddor commented Jun 6, 2023

@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

@ioquatix
Copy link
Member

ioquatix commented Jun 6, 2023

Okay great, thanks, I'll check what's going on.

@ioquatix
Copy link
Member

ioquatix commented Jun 6, 2023

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.

@paddor
Copy link
Contributor Author

paddor commented Jun 7, 2023

@ioquatix Thank you for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants