Created
December 21, 2014 07:48
-
-
Save clicube/61d3059f4ccac9ae5a79 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module StartStopDaemon | |
# Start or stop daemon process. | |
# | |
# * command (String or Symbol): | |
# [start] Create new instance with arguments ,call #start and create PID file. | |
# [stop] Call #stop, send TERM signal and remove PID file. | |
# [restart] Do stop and start. | |
# [status] Show whether the process is running nor not. | |
# [-h|--help|help] Show usage. | |
# | |
# * options (Hash): | |
# [:pidfile] Filepath of pidfile. Default is <classname>.pid in current directory. | |
# [:logfile] Filepath of logfile. Default is <classname>.log in current directory. | |
# [:workdir] If this is set, working directory will be changed. | |
# [:synclog] Set to File#sync of logfile. Default is true. | |
# [:args] Arguments for initialize the extended class. | |
def start_stop_daemon! command, options={} | |
opt = Object.new | |
class << opt | |
attr_accessor :pidfile, :workdir, :logfile, :synclog, :args | |
end | |
options.each do |k,v| | |
opt.send "#{k}=",v | |
end | |
yield opt if block_given? | |
classname = self.name.split('::').last | |
opt.pidfile ||= "#{classname}.pid" | |
opt.logfile ||= "#{classname}.log" | |
opt.workdir ||= Dir.pwd | |
opt.synclog ||= true | |
case command.to_s | |
when 'start' | |
start opt | |
when 'stop' | |
stop opt | |
when 'restart' | |
restart opt | |
when 'status' | |
status opt | |
when 'help', '-h', '--help' | |
help opt | |
exit 0 | |
else | |
puts "Invalid command" | |
help opt | |
exit 1 | |
end | |
end | |
private | |
def get_pid pidfile #:nodoc: | |
return nil unless File.readable?(pidfile) | |
File.open(pidfile,"r") do |f| | |
return f.gets.to_i | |
end | |
end | |
def alive? pid #:nodoc: | |
Process.kill 0, pid | |
rescue Errno::ESRCH | |
false | |
end | |
def start options #:nodoc: | |
unless File.writable?(File.dirname(options.logfile)) | |
STDERR.puts "Unable to write log file to #{options.logfile}" | |
exit 1 | |
end | |
unless File.writable?(File.dirname(options.pidfile)) | |
STDERR.puts "Unable to write pid file to #{options.pidfile}" | |
exit 1 | |
end | |
if (pid = get_pid(options.pidfile)) && alive?(pid) | |
STDERR.puts "Process is already running (PID: #{pid})" | |
exit 1 | |
end | |
fork do | |
Process.setsid | |
exit if fork | |
File.open(options.pidfile, "w") do |f| | |
f << Process.pid | |
end | |
Dir.chdir options.workdir | |
if options.logfile | |
old_umask = File.umask 0000 | |
log = File.new(options.logfile, "a") | |
File.umask old_umask | |
log.sync = options.synclog | |
STDIN.reopen "/dev/null" | |
STDOUT.reopen log | |
STDERR.reopen STDOUT | |
end | |
instance = self.new *(options.args||[]) | |
trap("TERM") do | |
if defined?(instance.stop) == "method" | |
instance.stop | |
end | |
exit | |
end | |
if defined?(instance.start) == "method" | |
instance.start | |
end | |
end | |
5.times do | |
sleep 0.1 | |
if (pid = get_pid(options.pidfile)) && alive?(pid) | |
puts "Started process (PID: #{pid})" | |
exit 0 | |
end | |
end | |
puts "Unable to start process" | |
exit 1 | |
end | |
def stop options, on_restart=false #:nodoc: | |
unless pid = get_pid(options.pidfile) | |
puts "Unable to read PID file #{options.pidfile}" | |
exit 1 | |
end | |
unless alive? pid | |
puts "Process is not running (PID: #{pid})" | |
exit 1 | |
end | |
Process.kill :TERM, pid | |
5.times do | |
sleep 0.1 | |
unless alive? pid | |
File.delete options.pidfile | |
puts "Stopped process (PID: #{pid})" | |
if on_restart | |
return true | |
else | |
exit 0 | |
end | |
end | |
end | |
puts "Unable to stop process (PID: #{pid})" | |
exit 1 | |
end | |
def restart options #:nodoc: | |
stop options,true | |
start options | |
end | |
def status options #:nodoc: | |
unless pid = get_pid(options.pidfile) | |
puts "Unable to read PID file #{options.pidfile}" | |
exit 0 | |
end | |
unless alive? pid | |
puts "Process is not running (PID: #{pid})" | |
exit 0 | |
end | |
puts "process is running (PID: #{pid})" | |
exit 0 | |
end | |
def help options #:nodoc: | |
puts "usage: #{$0} <start|stop|restart|status|help>" | |
end | |
end | |
if $0 == __FILE__ | |
class Neko | |
extend StartStopDaemon | |
def initialize *args | |
puts "initialized with #{args}" | |
sleep | |
end | |
end | |
Neko.start_stop_daemon! ARGV[0] do |neko| | |
neko.logfile = File.dirname(__FILE__) + "/neko.log" | |
neko.pidfile = File.dirname(__FILE__) + "/neko.pid" | |
neko.args = :nyan | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment