1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
require 'daemons/pid'
module Daemons
# === What is a Pid-File?
# A <i>Pid-File</i> is a file containing the <i>process identification number</i>
# (pid) that is stored in a well-defined location of the filesystem thus allowing other
# programs to find out the pid of a running script.
#
# Daemons needs the pid of the scripts that are currently running in the background
# to send them so called _signals_. Daemons uses the +TERM+ signal to tell the script
# to exit when you issue a +stop+ command.
#
# === How does a Pid-File look like?
#
# Pid-Files generated by Daemons have to following format:
# <scriptname>_num<number>.pid
# (Note that <tt>_num<number></tt> is omitted if only one instance of the script can
# run at any time)
#
# Each file just contains one line with the pid as string (for example <tt>6432</tt>).
#
# === Where are the Pid-Files stored?
#
# Daemons is configurable to store the Pid-Files relative to three different locations:
# 1. in a directory relative to the directory where the script (the one that is supposed to run
# as a daemon) resides (<tt>:script</tt> option for <tt>:dir_mode</tt>)
# 2. in a directory given by <tt>:dir</tt> (<tt>:normal</tt> option for <tt>:dir_mode</tt>)
# 3. in the preconfigured directory <tt>/var/run</tt> (<tt>:system</tt> option for <tt>:dir_mode</tt>)
#
class PidFile < Pid
DEFAULT_PID_DELIMITER = '_num'
attr_reader :dir, :progname, :multiple, :number, :pid_delimiter
def self.find_files(dir, progname, delete = false, pid_delimiter = nil)
files = Dir[File.join(dir, "#{progname}#{pid_delimiter || DEFAULT_PID_DELIMITER}*.pid")]
files = Dir[File.join(dir, "#{progname}.pid")] if files.size == 0
files.delete_if { |f| not (File.file?(f) and File.readable?(f)) }
if delete
files.delete_if do |f|
pid = File.open(f) { |h| h.read }.to_i
rsl = !Pid.running?(pid)
if rsl
begin; File.unlink(f); rescue ::Exception; end
yield(pid, f) if block_given?
end
rsl
end
end
files
end
def self.existing(path)
new_instance = PidFile.allocate
new_instance.instance_variable_set(:@path, path)
def new_instance.filename
@path
end
new_instance
end
def initialize(dir, progname, multiple = false, pid_delimiter = nil)
@dir = File.expand_path(dir)
@progname = progname
@multiple = multiple
@pid_delimiter = pid_delimiter || DEFAULT_PID_DELIMITER
@number = nil
@number = 0 if multiple
if multiple
while File.exist?(filename) && @number < 1024
@number += 1
end
if @number >= 1024
fail RuntimeException('cannot run more than 1024 instances of the application')
end
end
end
def filename
suffix = "#{pid_delimiter}#{@number}" if @number
File.join(@dir, "#{@progname}#{suffix}.pid")
end
def exist?
File.exist? filename
end
def pid=(p)
File.open(filename, 'w') do |f|
f.chmod(0644)
f.puts p # Process.pid
end
end
def cleanup
File.delete(filename) if pid == Process.pid
end
def zap
File.delete(filename) if exist?
end
def pid
begin
File.open(filename) do |f|
p = f.gets.to_i
return nil if p == 0 # Otherwise an invalid pid file becomes pid 0
return p
end
rescue ::Exception
return nil
end
end
end
end
|