class Sanford::Process

Constants

HALT
RESTART
STOP
WAIT_FOR_SIGNALS_TIMEOUT

Attributes

client_fds[R]
name[R]
pid_file[R]
restart_cmd[R]
server[R]
server_fd[R]
server_ip[R]
server_port[R]
signal_io[R]

Public Class Methods

new(server, options = nil) click to toggle source
# File lib/sanford/process.rb, line 17
def initialize(server, options = nil)
  options ||= {}
  @server = server
  @name   = "sanford: #{@server.process_label}"
  @logger = @server.logger

  @pid_file    = PIDFile.new(@server.pid_file)
  @signal_io   = IOPipe.new
  @restart_cmd = RestartCmd.new

  @server_ip   = @server.configured_ip
  @server_port = @server.configured_port
  @server_fd   = if !ENV['SANFORD_SERVER_FD'].to_s.empty?
    ENV['SANFORD_SERVER_FD'].to_i
  end
  @listen_args = @server_fd ? [@server_fd] : [@server_ip, @server_port]

  @client_fds = ENV['SANFORD_CLIENT_FDS'].to_s.split(',').map(&:to_i)

  skip_daemonize = ignore_if_blank(ENV['SANFORD_SKIP_DAEMONIZE'])
  @daemonize = !!options[:daemonize] && !skip_daemonize
end

Public Instance Methods

daemonize?() click to toggle source
# File lib/sanford/process.rb, line 66
def daemonize?; @daemonize; end
run() click to toggle source
# File lib/sanford/process.rb, line 40
def run
  ::Process.daemon(true) if self.daemonize?
  log "Starting Sanford server for #{@server.name}..."

  @server.listen(*@listen_args)
  log "Listening on #{@server.ip}:#{@server.port}"

  $0 = @name
  @pid_file.write
  log "PID: #{@pid_file.pid}"

  @signal_io.setup
  trap_signals(@signal_io)

  start_server(@server, @client_fds)

  signal = catch(:signal) do
    wait_for_signals(@signal_io, @server)
  end
  @signal_io.teardown

  run_restart_cmd(@restart_cmd, @server) if signal == RESTART
ensure
  @pid_file.remove
end

Private Instance Methods

handle_signal(signal, server) click to toggle source
# File lib/sanford/process.rb, line 102
def handle_signal(signal, server)
  log "Got '#{signal}' signal"
  case signal
  when HALT
    server.halt(true)
  when STOP
    server.stop(true)
  when RESTART
    server.pause(true)
  end
  throw :signal, signal
end
ignore_if_blank(value, &block) click to toggle source
# File lib/sanford/process.rb, line 124
def ignore_if_blank(value, &block)
  block ||= proc{ |v| v }
  block.call(value) if value && !value.empty?
end
log(message) click to toggle source
# File lib/sanford/process.rb, line 120
def log(message)
  @logger.info "[Sanford] #{message}"
end
run_restart_cmd(restart_cmd, server) click to toggle source
# File lib/sanford/process.rb, line 115
def run_restart_cmd(restart_cmd, server)
  log "Restarting #{server.name} daemon..."
  restart_cmd.run(server)
end
start_server(server, client_fds) click to toggle source
# File lib/sanford/process.rb, line 70
def start_server(server, client_fds)
  server.start(client_fds)
  log "#{server.name} server started and ready."
rescue StandardError => exception
  log "#{server.name} server never started."
  raise exception
end
trap_signal(signal, &block) click to toggle source
# File lib/sanford/process.rb, line 84
def trap_signal(signal, &block)
  ::Signal.trap(signal, &block)
rescue ArgumentError
  log "'#{signal}' signal not supported"
end
trap_signals(signal_io) click to toggle source
# File lib/sanford/process.rb, line 78
def trap_signals(signal_io)
  trap_signal('INT'){  signal_io.write(HALT) }
  trap_signal('TERM'){ signal_io.write(STOP) }
  trap_signal('USR2'){ signal_io.write(RESTART) }
end
wait_for_signals(signal_io, server) click to toggle source
# File lib/sanford/process.rb, line 90
def wait_for_signals(signal_io, server)
  loop do
    ready = signal_io.wait(WAIT_FOR_SIGNALS_TIMEOUT)
    handle_signal(signal_io.read, server) if ready

    if !server.running?
      log "Server crashed, restarting"
      start_server(server, server.client_file_descriptors)
    end
  end
end