Ruby Daemon Module
Join the DZone community and get the full member experience.
Join For FreeThe following code lets you implement a daemon very easily, and also lets you write cleanup code.
Update: I made some small changes to make it look slightly better.
require 'fileutils'
module Daemon
WorkingDirectory = File.expand_path(File.dirname(__FILE__))
class Base
def self.pid_fn
File.join(WorkingDirectory, "#{name}.pid")
end
def self.daemonize
Controller.daemonize(self)
end
end
module PidFile
def self.store(daemon, pid)
File.open(daemon.pid_fn, 'w') {|f| f << pid}
end
def self.recall(daemon)
IO.read(daemon.pid_fn).to_i rescue nil
end
end
module Controller
def self.daemonize(daemon)
case !ARGV.empty? && ARGV[0]
when 'start'
start(daemon)
when 'stop'
stop(daemon)
when 'restart'
stop(daemon)
start(daemon)
else
puts "Invalid command. Please specify start, stop or restart."
exit
end
end
def self.start(daemon)
fork do
Process.setsid
exit if fork
PidFile.store(daemon, Process.pid)
Dir.chdir WorkingDirectory
File.umask 0000
STDIN.reopen "/dev/null"
STDOUT.reopen "/dev/null", "a"
STDERR.reopen STDOUT
trap("TERM") {daemon.stop; exit}
daemon.start
end
end
def self.stop(daemon)
if !File.file?(daemon.pid_fn)
puts "Pid file not found. Is the daemon started?"
exit
end
pid = PidFile.recall(daemon)
FileUtils.rm(daemon.pid_fn)
pid && Process.kill("TERM", pid)
end
end
end
To use it, you can do something like the following:
class Counter < Daemon::Base
def self.start
@a = 0
loop do
@a += 1
end
end
def self.stop
File.open('result', 'w') {|f| f.puts "a = #{@a}"}
end
end
Counter.daemonize
Opinions expressed by DZone contributors are their own.
Comments