class Sigurd::SignalHandler

Class that takes any object with a “start” and “stop” method and catches signals to ask them to stop nicely.

Constants

SIGNALS

Attributes

reader[R]
runner[R]
signal_queue[R]
writer[R]

Public Class Methods

new(runner) click to toggle source

Takes any object that responds to the `start` and `stop` methods. @param runner[#start, stop]

# File lib/sigurd/signal_handler.rb, line 12
def initialize(runner)
  @signal_queue = []
  @reader, @writer = IO.pipe
  @runner = runner
end

Public Instance Methods

run!() click to toggle source

Run the runner.

# File lib/sigurd/signal_handler.rb, line 19
def run!
  setup_signals
  @runner.start

  loop do
    case signal_queue.pop
    when *SIGNALS
      @runner.stop
      break
    else
      ready = IO.select([reader, writer])

      # drain the self-pipe so it won't be returned again next time
      reader.read_nonblock(1) if ready[0].include?(reader)
    end
  end
end

Private Instance Methods

prepend_handler(signal) { || ... } click to toggle source

stackoverflow.com/questions/29568298/run-code-when-signal-is-sent-but-do-not-trap-the-signal-in-ruby

# File lib/sigurd/signal_handler.rb, line 42
def prepend_handler(signal)
  previous = Signal.trap(signal) do
    previous = -> { raise SignalException, signal } unless previous.respond_to?(:call)
    yield
    previous.call
  end
end
setup_signals() click to toggle source

Trap signals using the self-pipe trick.

# File lib/sigurd/signal_handler.rb, line 51
def setup_signals
  at_exit { @runner&.stop }
  SIGNALS.each do |signal|
    prepend_handler(signal) do
      unblock(signal)
    end
  end
end
unblock(signal) click to toggle source

Save the signal to the queue and continue on. @param signal [Symbol]

# File lib/sigurd/signal_handler.rb, line 62
def unblock(signal)
  writer.write_nonblock('.')
  signal_queue << signal
end