class Restartable

Main interface

Constants

WAIT_SIGNALS

Public Class Methods

new(options = {}, &block) click to toggle source
# File lib/restartable.rb, line 18
def initialize(options = {}, &block)
  @on_restart = Array(options[:on_restart])
  @block = block
  run!
end
version() click to toggle source
# File lib/restartable.rb, line 12
def self.version
  Gem.loaded_specs['restartable'].version.to_s
rescue
  'DEV'
end

Private Instance Methods

children_pids() click to toggle source
# File lib/restartable.rb, line 115
def children_pids
  pgrp = Process.getpgrp
  Sys::ProcTable.ps.select do |pe|
    pgrp == case
    when pe.respond_to?(:pgid) then pe.pgid
    when pe.respond_to?(:pgrp) then pe.pgrp
    when pe.respond_to?(:ppid) then pe.ppid
    else fail 'Can\'t find process group id'
    end
  end.map(&:pid) - [$PROCESS_ID]
end
interrupt!() click to toggle source
# File lib/restartable.rb, line 50
def interrupt!
  if @interrupted
    @stop = true
    $stderr << "Don't restart!\n".red.bold
  else
    @interrupted = true
  end
end
kill_children!() click to toggle source
# File lib/restartable.rb, line 72
def kill_children!
  until children_pids.empty?
    $stderr << "Killing children…\n".yellow.bold

    signal_pair = 0

    begin
      time, signal = WAIT_SIGNALS[signal_pair]
      Timeout.timeout(time) do
        Process.waitall
        wait_children
      end
    rescue Timeout::Error
      $stderr << "…SIG#{signal}…\n".yellow
      signal_children!(signal)
      retry if WAIT_SIGNALS[signal_pair += 1]
    end
  end
end
run!() click to toggle source
# File lib/restartable.rb, line 26
def run!
  Signal.trap('INT'){ interrupt! }
  Signal.trap('TERM'){ terminate! }

  until @stop
    @interrupted = nil
    $stderr << "^C to restart, double ^C to stop\n".green
    @cpid = fork do
      Signal.trap('INT', 'DEFAULT')
      Signal.trap('TERM', 'DEFAULT')
      @block.call
    end
    sleep 0.1 until @interrupted
    kill_children!
    break if @stop

    $stderr << "Waiting ^C 0.5 second than restart…\n".yellow.bold
    sleep 0.5
    break if @stop

    @on_restart.each(&:call)
  end
end
signal_children!(signal) click to toggle source
# File lib/restartable.rb, line 105
def signal_children!(signal)
  children_pids.each do |pid|
    begin
      Process.kill(signal, pid)
    rescue Errno::ESRCH
      next
    end
  end
end
terminate!() click to toggle source
# File lib/restartable.rb, line 59
def terminate!
  interrupt!
  interrupt!
end
wait_children() click to toggle source
# File lib/restartable.rb, line 92
def wait_children
  children_pids.each do |pid|
    begin
      loop do
        Process.kill(0, pid)
        sleep 1
      end
    rescue Errno::ESRCH
      next
    end
  end
end