class ServerEngine::ProcessManager::Monitor

Attributes

command_sender_pipe[RW]
last_heartbeat_time[RW]
pid[R]

Public Class Methods

new(pid, opts={}) click to toggle source
# File lib/serverengine/process_manager.rb, line 289
def initialize(pid, opts={})
  @pid = pid

  @enable_heartbeat = opts[:enable_heartbeat]
  @heartbeat_timeout = opts[:heartbeat_timeout]

  @graceful_kill_signal   = opts[:graceful_kill_signal]
  @graceful_kill_timeout  = opts[:graceful_kill_timeout]
  @graceful_kill_interval = opts[:graceful_kill_interval]
  @graceful_kill_interval_increment = opts[:graceful_kill_interval_increment]

  @immediate_kill_signal   = opts[:immediate_kill_signal]
  @immediate_kill_timeout  = opts[:immediate_kill_timeout]
  @immediate_kill_interval = opts[:immediate_kill_interval]
  @immediate_kill_interval_increment = opts[:immediate_kill_interval_increment]

  @error = false
  @last_heartbeat_time = Time.now
  @next_kill_time = nil
  @graceful_kill_start_time = nil
  @immediate_kill_start_time = nil
  @kill_count = 0

  @command_sender_pipe = nil
end

Public Instance Methods

heartbeat_delay() click to toggle source
# File lib/serverengine/process_manager.rb, line 318
def heartbeat_delay
  now = Time.now
  now - @last_heartbeat_time
end
join() click to toggle source
# File lib/serverengine/process_manager.rb, line 359
def join
  pid = @pid
  return nil unless pid

  begin
    pid, status = Process.waitpid2(pid)
    code = status
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    code = $!
  end
  @pid = nil

  return code
end
send_command(command) click to toggle source
# File lib/serverengine/process_manager.rb, line 335
def send_command(command)
  @command_sender_pipe.write(command) if @command_sender_pipe
end
send_signal(sig) click to toggle source
# File lib/serverengine/process_manager.rb, line 323
def send_signal(sig)
  pid = @pid
  return nil unless pid

  begin
    Process.kill(sig, pid)
    return true
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    return false
  end
end
start_graceful_stop!() click to toggle source
# File lib/serverengine/process_manager.rb, line 375
def start_graceful_stop!
  if ServerEngine.windows?
    # heartbeat isn't supported on Windows
    send_command("GRACEFUL_STOP\n")
  else
    now = Time.now
    @next_kill_time ||= now
    @graceful_kill_start_time ||= now
  end
end
start_immediate_stop!() click to toggle source
# File lib/serverengine/process_manager.rb, line 386
def start_immediate_stop!
  if ServerEngine.windows?
    # heartbeat isn't supported on Windows
    system("taskkill /f /pid #{@pid}")
  else
    now = Time.now
    @next_kill_time ||= now
    @immediate_kill_start_time ||= now
  end
end
tick(now=Time.now) click to toggle source
# File lib/serverengine/process_manager.rb, line 397
def tick(now=Time.now)
  pid = @pid
  return false unless pid

  if !@immediate_kill_start_time
    # check heartbeat timeout or escalation
    if (
        # heartbeat timeout
        @enable_heartbeat &&
        heartbeat_delay >= @heartbeat_timeout
       ) || (
         # escalation
         @graceful_kill_start_time &&
         @graceful_kill_timeout >= 0 &&
         @graceful_kill_start_time < now - @graceful_kill_timeout
       )
      # escalate to immediate kill
      @kill_count = 0
      @immediate_kill_start_time = now
      @next_kill_time = now
    end
  end

  if !@next_kill_time || @next_kill_time > now
    # expect next tick
    return true
  end

  # send signal now

  if @immediate_kill_start_time
    interval = @immediate_kill_interval
    interval_incr = @immediate_kill_interval_increment
    if @immediate_kill_timeout >= 0 &&
        @immediate_kill_start_time <= now - @immediate_kill_timeout
      # escalate to SIGKILL
      signal = :KILL
    else
      signal = @immediate_kill_signal
    end

  else
    signal = @graceful_kill_signal
    interval = @graceful_kill_interval
    interval_incr = @graceful_kill_interval_increment
  end

  begin
    if ServerEngine.windows? && (signal == :KILL || signal == :SIGKILL)
      system("taskkill /f /pid #{pid}")
    else
      Process.kill(signal, pid)
    end
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    @pid = nil
    return false
  end

  @next_kill_time = now + interval + interval_incr * @kill_count
  @kill_count += 1

  # expect next tick
  return true
end
try_join() click to toggle source
# File lib/serverengine/process_manager.rb, line 339
def try_join
  pid = @pid
  return true unless pid

  begin
    pid, status = Process.waitpid2(pid, Process::WNOHANG)
    code = status
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    code = $!
  end

  if code
    @pid = nil
    return code
  end

  return false
end