class Vines::Daemon

Fork the current process into the background and manage pid files so we can kill the process later.

Public Class Methods

new(args) click to toggle source

Configure a new daemon process. Arguments hash can include the following keys: :pid (pid file name, required), :stdin, :stdout, :stderr (default to /dev/null)

# File lib/vines/daemon.rb, line 12
def initialize(args)
  @pid = args[:pid]
  raise ArgumentError.new('pid file is required') unless @pid
  raise ArgumentError.new('pid must be a file name') if File.directory?(@pid)
  raise ArgumentError.new('pid file must be writable') unless File.writable?(File.dirname(@pid))
  @stdin, @stdout, @stderr = [:stdin, :stdout, :stderr].map {|k| args[k] || '/dev/null' }
end

Public Instance Methods

pid() click to toggle source

Returns the numeric process ID from the pid file. If the pid file does not exist, returns nil.

# File lib/vines/daemon.rb, line 52
def pid
  File.read(@pid).to_i if File.exists?(@pid) 
end
running?() click to toggle source

Returns true if the process is running as determined by the numeric pid stored in the pid file created by a previous call to start.

# File lib/vines/daemon.rb, line 39
def running?
  begin
    pid && Process.kill(0, pid)
  rescue Errno::ESRCH
    delete_pid
    false
  rescue Errno::EPERM
    true
  end
end
start() click to toggle source

Fork the current process into the background to start the daemon. Do nothing if the daemon is already running.

# File lib/vines/daemon.rb, line 22
def start
  daemonize unless running?
end
stop() click to toggle source

Use the pid stored in the pid file created from a previous call to start to send a TERM signal to the process. Do nothing if the daemon is not running.

# File lib/vines/daemon.rb, line 29
def stop
  10.times do
    break unless running?
    Process.kill('TERM', pid)
    sleep(0.1)
  end
end

Private Instance Methods

daemonize() click to toggle source

Fork process into background twice to release it from the controlling tty. Point open file descriptors shared with the parent process to separate destinations (e.g. /dev/null).

# File lib/vines/daemon.rb, line 65
def daemonize
  exit if fork
  Process.setsid
  exit if fork
  Dir.chdir('/')
  $stdin.reopen(@stdin)
  $stdout.reopen(@stdout, 'a').sync = true
  $stderr.reopen(@stderr, 'a').sync = true
  File.open(@pid, 'w') {|f| f.write(Process.pid) }
  at_exit { delete_pid }
  trap('TERM') { exit }
end
delete_pid() click to toggle source
# File lib/vines/daemon.rb, line 58
def delete_pid
  File.delete(@pid) if File.exists?(@pid)
end