Class: Servolux::PidFile

Inherits:
Object
  • Object
show all
Defined in:
lib/servolux/pid_file.rb

Overview

Synopsis

The PidFile manages the lifecycle of a PID file.

Details

A PID file contains the process ID of a given program. This file can be used by the program to indicate that it started successfully. The file can be used programmatically to look up the process ID and send signals to the program. The file can be used to ensure two instances of the same program are not started at the same time.

The PidFile class supports creating and deleting PID files. Methods are provided to check if the program associated with the PID is alive?. Signals can be sent to the program using the kill method.

Examples

Here is a simple example creating a PID file in the "/var/run" directory.

pid_file = Servolux::PidFile.new(:name => "test", :path => "/var/run")
pid_file.filename  #=> "/var/run/test.pid"
pid_file.write

From another process we can access this PID file and send a HUP signal to the program.

pid_file = Servolux::PidFile.new(:name => "test", :path => "/var/run")
pid_file.kill("HUP") if pid_file.alive?

Constant Summary collapse

DEFAULT_MODE =
0640

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) {|_self| ... } ⇒ PidFile

Create a new PID file instance.

opts - The options Hash :name - the name of the program :path - path to the PID file location :mode - file permissions mode :logger - logger for outputting messages

Yields:

  • (_self)

Yield Parameters:



46
47
48
49
50
51
52
53
# File 'lib/servolux/pid_file.rb', line 46

def initialize( opts = {} )
  @name   = opts.fetch(:name, $0)
  @path   = opts.fetch(:path, ".")
  @mode   = opts.fetch(:mode, DEFAULT_MODE)
  @logger = opts.fetch(:logger, Servolux::NullLogger())

  yield self if block_given?
end

Instance Attribute Details

#loggerObject

logger for outputting messages



36
37
38
# File 'lib/servolux/pid_file.rb', line 36

def logger
  @logger
end

#modeObject

PID file permissions mode



35
36
37
# File 'lib/servolux/pid_file.rb', line 35

def mode
  @mode
end

#nameObject

the process name



33
34
35
# File 'lib/servolux/pid_file.rb', line 33

def name
  @name
end

#pathObject

the path to the PID file



34
35
36
# File 'lib/servolux/pid_file.rb', line 34

def path
  @path
end

Instance Method Details

#alive?Boolean

Returns true if the process is currently running. Returns false if this is not the case. The status of the process is determined by sending signal 0 to the process.

Returns:



122
123
124
125
126
127
128
129
130
# File 'lib/servolux/pid_file.rb', line 122

def alive?
  pid = self.pid
  return if pid.nil?

  Process.kill(0, pid)
  true
rescue Errno::ESRCH, Errno::ENOENT
  false
end

#deleteObject

Delete the PID file if it exists. This method first checks that the current process PID is the same as the PID stored in the file. If the PIDs do not match, then this method returns nil without taking any action.

Returns the filename of the deleted file or nil if no action was taken. Raises Errno::EACCESS if you do not have permission to delete the file.



82
83
84
85
86
87
88
# File 'lib/servolux/pid_file.rb', line 82

def delete
  return unless pid == Process.pid
  fn = filename
  logger.debug "Deleting pid file #{fn.inspect}"
  File.delete fn
  fn
end

#delete!Object

Forcibly delete the PID file if it exists. This method does NOT check that the current process PID against the PID stored in the file.

Returns the filename of the deleted file or nil if no action was taken. Raises Errno::EACCESS if you do not have permission to delete the file.



95
96
97
98
99
100
101
# File 'lib/servolux/pid_file.rb', line 95

def delete!
  return unless exist?
  fn = filename
  logger.debug "Deleting pid file #{fn.inspect}"
  File.delete fn
  fn
end

#exist?Boolean

Returns true if the PID file exists. Returns false otherwise.

Returns:



104
105
106
# File 'lib/servolux/pid_file.rb', line 104

def exist?
  File.exist? filename
end

#filenameObject

Returns the full name of the PID file including path and extension.



56
57
58
59
60
# File 'lib/servolux/pid_file.rb', line 56

def filename
  fn = name.to_s.downcase.tr(" ","_") + ".pid"
  fn = File.join(path, fn) unless path.nil?
  fn
end

#kill(signal = 'INT') ⇒ Object

Send a signal the process identified by the PID file. The default signal to send is 'INT' (2). The signal can be given either as a string or a signal number.

signal - The signal to send to the process (String or Integer)

Returns an Integer or nil if an error was encountered.



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/servolux/pid_file.rb', line 139

def kill( signal = 'INT' )
  pid = self.pid
  return if pid.nil?

  signal = Signal.list.invert[signal] if signal.is_a?(Integer)
  logger.info "Killing PID #{pid} with #{signal}"
  Process.kill(signal, pid)

rescue Errno::EINVAL
  logger.error "Failed to kill PID #{pid} with #{signal}: " \
               "'#{signal}' is an invalid or unsupported signal number."
  nil
rescue Errno::EPERM
  logger.error "Failed to kill PID #{pid} with #{signal}: " \
               "Insufficient permissions."
  nil
rescue Errno::ESRCH
  logger.error "Failed to kill PID #{pid} with #{signal}: " \
               "Process is deceased or zombie."
  nil
rescue Errno::EACCES => err
  logger.error err.message
  nil
rescue Errno::ENOENT => err
  logger.error "Could not find a PID file at #{pid_file.inspect}. " \
               "Most likely the process is no longer running."
  nil
rescue Exception => err
  unless err.is_a?(SystemExit)
    logger.error "Failed to kill PID #{pid} with #{signal}: #{err.message}"
  end
  nil
end

#pidObject

Returns the numeric PID read from the file or nil if the file does not exist. If you do not have permission to access the file nil is returned.



110
111
112
113
114
115
116
117
# File 'lib/servolux/pid_file.rb', line 110

def pid
  fn = filename
  Integer(File.read(fn).strip) if File.exist?(fn)
rescue Errno::EACCES => err
  logger.error "You do not have access to the PID file at " \
               "#{fn.inspect}: #{err.message}"
  nil
end

#write(pid = Process.pid) ⇒ Object

Writes the given pid to the PID file. The pid defaults to the current process ID.

pid - The process ID to write to the file

Returns the filename of PID file. Raises Errno::EACCESS if you do not have permission to write the file.



69
70
71
72
73
74
# File 'lib/servolux/pid_file.rb', line 69

def write( pid = Process.pid )
  fn = filename
  logger.debug "Writing pid file #{fn.inspect}"
  File.open(fn, 'w', mode) { |fd| fd.write(pid.to_s) }
  fn
end