linkyndy
linkyndy

Reputation: 17920

Signal handling with Queue in Ruby

I am trying to do signal handling for my CLI app. I would like to avoid the self-pipe "trick", but also consider that using a per thread list of signals that is periodically polled is not the best idea. Hence, my idea was to use Queue to block until a new signal arrives. Here is my attempt:

class CLI
  def initialize
    @manager = Thread.new { sleep }
    @signal_queue = Queue.new

    setup_signal_handlers
  end

  def run
    loop do
      signal = @signal_queue.pop # This doesn't unblock!
      handle_signal(signal)
    end
  rescue Interrupt
    exit
  end

  private

  def handle_signal(signal)
    case signal
    when 'INT'
      raise Interrupt
    end
  end

  def setup_signal_handlers
    %w(INT).each do |signal|
      trap signal do
        @signal_queue.push signal # This works. @signal_queue.size is incremented
      end
    end
  end
end

# Run with CLI.new.run and hit ctrl^C

where I've simplified @manager for clarity. The problem is that, even if the signal is trapped and pushed to @signal_queue, the blocking call @signal_queue.pop doesn't pick it up. What am I missing here?

Upvotes: 0

Views: 323

Answers (1)

Jyrki
Jyrki

Reputation: 568

It looks like you're experiencing Ruby bug #12405: Queue doesn't work inside of trap. Luckily this bug got fixed in Ruby versions 2.2.7, 2.3.4, and 2.4.1 (2.5.0 already includes that fix); therefore your code behaves as expected after upgrading to a more recent Ruby version.

Upvotes: 1

Related Questions