class ProcessManager::Daemon::Master
Attributes
children[RW]
Public Class Methods
abort()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 300 def self.abort Kernel.abort end
child_class()
click to toggle source
please override
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 327 def self.child_class ::ProcessManager::Daemon::Child end
clean_stale_pid()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 304 def self.clean_stale_pid puts "Pidfile #{pid_file} present but no matching process running - cleaning up" ::FileUtils.rm(pid_file) end
description(pid = $$)
click to toggle source
please override
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 322 def self.description(pid = $$) "master #{pid}" end
find_pid()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 309 def self.find_pid File.read(pid_file).chomp.to_i rescue nil end
log_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 90 def self.log_file File.join(ProcessManager::Config.config[:log_dir], "#{ProcessManager::Config.config[:program_name]}.#{pid_description}.log") end
new()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 12 def initialize @children = {} ProcessManager.set_program_name(description) ensure_validate_configuration dropped_privileges = drop_privileges ProcessManager::Log.init(log_file) if dropped_privileges ProcessManager::Log.info("Dropped privileges to group: #{Etc.getgrgid(Process.gid).name} (gid = #{Process.gid})") ProcessManager::Log.info("Dropped privileges to user: #{Etc.getpwuid(Process.uid).name} (uid = #{Process.uid})") end after_initialize end
pid_description()
click to toggle source
please override
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 82 def self.pid_description "ProcessManager" end
pid_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 65 def self.pid_file File.join(ProcessManager::Config.config[:pid_dir], "#{ProcessManager::Config.config[:program_name]}.#{self.pid_description}.pid") end
pid_lock_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 69 def self.pid_lock_file File.join(ProcessManager::Config.config[:pid_dir], "#{ProcessManager::Config.config[:program_name]}.pid.lock") end
restart()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 45 def self.restart stop sleep 1 start end
start()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 34 def self.start pid = fork do new.start end Process.detach pid end
status()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 51 def self.status if pid = find_pid if ProcessManager::process_running?(pid) pid else clean_stale_pid nil end else # does not run nil end end
stop()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 41 def self.stop new.stop end
Public Instance Methods
after_initialize()
click to toggle source
please override
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 26 def after_initialize # hook end
child_class()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 317 def child_class self.class.child_class end
cleanup_and_exit()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 218 def cleanup_and_exit SimplePid.cleanup!(pid_file) @file_lock.close exit end
cleanup_dead_child(dead_child)
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 242 def cleanup_dead_child(dead_child) ProcessManager::Log.info "#{description}: been told to replace child #{dead_child.inspect}" # delete given child if index = children.key(dead_child) children.delete(index) end # check all other children children.each do |child_index, child_pid| begin dead_child = Process.waitpid(child_pid, Process::WNOHANG) if index = children.key(dead_child) children.delete(index) end rescue Errno::ECHILD end end replace_terminated_children end
description(pid = $$)
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 313 def description(pid = $$) self.class.description(pid) end
drop_privileges()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 98 def drop_privileges runas_user = ProcessManager::Config.config[:user] return false if runas_user.blank? if runas_user == Etc.getpwuid(Process.uid).name return false elsif Process.uid != 0 raise "Can't drop privileges as unprivileged user. Please run this command as a privileged user." end if runas_user.present? uid = Etc.getpwnam(runas_user).uid if (group = ProcessManager::Config.config[:group]) && group.present? gid = Etc.getgrnam(group).gid else gid = Etc.getpwuid(uid).gid end Process.initgroups(runas_user, gid) Process::GID.change_privilege(gid) Process::UID.change_privilege(uid) true end false rescue Exception => e $stderr.puts "Failed to drop privileges: #{e.class} - #{e.message} - #{e.backtrace.join("\n")}" exit 1 end
ensure_validate_configuration()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 293 def ensure_validate_configuration if (errors = ProcessManager::Config.validate_config) errors.each{|error| puts error} end cleanup_and_exit unless errors.empty? end
handle_chld()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 224 def handle_chld if child = reap_child ProcessManager::Log.info "#{description}: Received CHLD - cleaning dead child process" cleanup_dead_child(child) else ProcessManager::Log.debug "#{description}: Received CHLD - ignoring as it looks like a child of a child" end end
handle_pid_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 164 def handle_pid_file @file_lock ||= File.open(pid_lock_file, File::RDWR|File::CREAT, 0644) lock_acquired = @file_lock.flock(File::LOCK_EX | File::LOCK_NB) if lock_acquired == false ProcessManager::Log.info("Could not acquire lock on #{pid_lock_file} - aborting start!") self.class.abort elsif File.exists?(pid_file) pid = self.class.find_pid if ProcessManager.process_running?(pid) puts "Pidfile #{pid_file} exists and process #{pid} is running - aborting start!" ProcessManager::Log.info("Pidfile #{pid_file} exists and process #{pid} is running - aborting start!") @file_lock.close self.class.abort else self.class.clean_stale_pid end end ::SimplePid.drop(pid_file) end
kill_children(sig)
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 284 def kill_children(sig) children.each do |index, child_pid| begin Process.kill(sig, child_pid) rescue Errno::ESRCH end end end
log_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 94 def log_file self.class.log_file end
pid_description()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 86 def pid_description self.class.pid_description end
pid_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 77 def pid_file self.class.pid_file end
pid_lock_file()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 73 def pid_lock_file self.class.pid_lock_file end
reap_child()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 233 def reap_child dead_child = nil begin dead_child = Process.wait rescue Errno::ECHILD end dead_child end
replace_terminated_children()
click to toggle source
make sure we have again as many child we need
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 264 def replace_terminated_children missing_children = ProcessManager::Config.config[:children] - children.values.size if missing_children > 0 ProcessManager::Log.info "#{description}: not enough child processes running - missing at least #{missing_children} - respawning" 0.upto(ProcessManager::Config.config[:children] - 1).each do |i| if children.has_key?(i) ProcessManager::Log.debug "#{description}: child #{i+1}/#{ProcessManager::Config.config[:children]} is still there" else Thread.new(i) do # Sleep for 5 seconds before spawning a new child. That way we can avoid fork storm due to child process bootstrap issues. sleep(5) spawn_child(i) end end end else ProcessManager::Log.debug "#{description}: no need to replace child processes" end end
spawn_child(index)
click to toggle source
spawn a new child and pass down out PID so that it can check if we are alive
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 194 def spawn_child(index) master_pid = $$ # need to store in order to pass down to child child_pid = fork do @file_lock.close child_class.new(index, master_pid).start end children[index] = child_pid ProcessManager::Log.info "#{description}: Spawned child #{index + 1}/#{ProcessManager::Config.config[:children]}" end
spawn_children()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 186 def spawn_children ProcessManager::Config.config[:children].times do |i| spawn_child(i) sleep ProcessManager::Config.config[:wait_between_spawning_children].to_i end end
start()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 127 def start @kill_signal_received=0; handle_pid_file validate_ssl_config trap_signals spawn_children puts "Started #{description} with #{ProcessManager::Config.config[:children]} children" ProcessManager::Log.info("Started #{description} with #{ProcessManager::Config.config[:children]} children") loop do # master does nothing apart from replacing dead children # and forwarding signals # To do that, it observes a kill_sig_received flag in every loop iteration if @kill_signal_received != 0 ProcessManager::Log.info "#{description}: Received #{@kill_signal_received} - stopping children and shutting down" kill_children(@kill_signal_received) @kill_signal_received=0 cleanup_and_exit end sleep 1 end end
stop()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 151 def stop if (pid = self.class.find_pid) puts "Stopping #{description(pid)}" ProcessManager::Log.info("Stopping #{description(pid)}") begin Process.kill('TERM', pid) rescue Errno::ESRCH end else puts "Nothing running that could be stopped" end end
trap_signals()
click to toggle source
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 204 def trap_signals # The QUIT & INT signals triggers a graceful shutdown. # The master shuts down immediately and forwards the signal to each child [:INT, :QUIT, :TERM].each do |sig| trap(sig) do @kill_signal_received=sig end end trap(:CHLD) do handle_chld end end
validate_ssl_config()
click to toggle source
please override
# File vendor/gems/process_manager/lib/process_manager/master.rb, line 31 def validate_ssl_config end