class Hutch::Waiter

Signal-handling class.

Currently, the signal USR2 performs a thread dump, while QUIT, TERM and INT all perform a graceful shutdown.

Constants

REGISTERED_SIGNALS
SHUTDOWN_SIGNALS
USER_SIGNALS

We have chosen a JRuby-supported signal

Attributes

sig_read[RW]
sig_write[RW]

Public Class Methods

supported_signals_of(list) click to toggle source
# File lib/hutch/waiter.rb, line 14
def self.supported_signals_of(list)
  list.keep_if { |s| Signal.list.keys.include?(s) }.tap do |result|
    result.delete('QUIT') if defined?(JRUBY_VERSION)
  end
end
wait_until_signaled() click to toggle source
# File lib/hutch/waiter.rb, line 25
def self.wait_until_signaled
  new.wait_until_signaled
end

Public Instance Methods

handle_shutdown_signal(sig) click to toggle source
# File lib/hutch/waiter.rb, line 62
def handle_shutdown_signal(sig)
  logger.info "caught SIG#{sig}, stopping hutch..."
end
handle_signal(sig) click to toggle source
# File lib/hutch/waiter.rb, line 44
def handle_signal(sig)
  raise ContinueProcessingSignals unless REGISTERED_SIGNALS.include?(sig)
  if user_signal?(sig)
    handle_user_signal(sig)
  else
    handle_shutdown_signal(sig)
  end
end
handle_user_signal(sig) click to toggle source

@raise ContinueProcessingSignals

# File lib/hutch/waiter.rb, line 54
def handle_user_signal(sig)
  case sig
  when 'USR2' then log_thread_backtraces
  else raise "Assertion failed - unhandled signal: #{sig.inspect}"
  end
  raise ContinueProcessingSignals
end
wait_until_signaled() click to toggle source
# File lib/hutch/waiter.rb, line 29
def wait_until_signaled
  self.sig_read, self.sig_write = IO.pipe

  register_signal_handlers

  begin
    wait_for_signal

    sig = sig_read.gets.strip
    handle_signal(sig)
  rescue ContinueProcessingSignals
    retry
  end
end

Private Instance Methods

backtrace_for(thread) click to toggle source
# File lib/hutch/waiter.rb, line 76
def backtrace_for(thread)
  if thread.backtrace
    thread.backtrace.join("\n")
  else
    '<no backtrace available>'
  end
end
log_thread_backtraces() click to toggle source
# File lib/hutch/waiter.rb, line 68
def log_thread_backtraces
  logger.info 'Requested a VM-wide thread stack trace dump...'
  Thread.list.each do |thread|
    logger.info "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
    logger.info backtrace_for(thread)
  end
end
register_signal_handlers() click to toggle source
# File lib/hutch/waiter.rb, line 90
def register_signal_handlers
  REGISTERED_SIGNALS.each do |sig|
    # This needs to be reentrant, so we queue up signals to be handled
    # in the run loop, rather than acting on signals here
    trap(sig) do
      sig_write.puts(sig)
    end
  end
end
user_signal?(sig) click to toggle source
# File lib/hutch/waiter.rb, line 100
def user_signal?(sig)
  USER_SIGNALS.include?(sig)
end
wait_for_signal() click to toggle source
# File lib/hutch/waiter.rb, line 86
def wait_for_signal
  IO.select([sig_read])
end