lib/rexec/daemon/controller.rb in rexec-1.1.12 vs lib/rexec/daemon/controller.rb in rexec-1.2.1

- old
+ new

@@ -15,178 +15,195 @@ require 'rexec/daemon/pidfile' require 'rexec/task' module RExec - module Daemon - # Daemon startup timeout - TIMEOUT = 5 - - # This module contains functionality related to starting and stopping the daemon, and code for processing command line input. - module Controller - # This function is called from the daemon executable. It processes ARGV and checks whether the user is asking for - # <tt>start</tt>, <tt>stop</tt>, <tt>restart</tt> or <tt>status</tt>. - def self.daemonize(daemon) - #puts "Running in #{WorkingDirectory}, logs in #{LogDirectory}" - case !ARGV.empty? && ARGV[0] - when 'start' - start(daemon) - status(daemon) - when 'stop' - stop(daemon) - status(daemon) - PidFile.cleanup(daemon) - when 'restart' - stop(daemon) - PidFile.cleanup(daemon) - start(daemon) - status(daemon) - when 'status' - status(daemon) - else - puts "Invalid command. Please specify start, restart, stop or status." - exit - end - end + module Daemon + # Daemon startup timeout + TIMEOUT = 5 - # This function starts the supplied daemon - def self.start(daemon) - puts "Starting daemon..." - - case PidFile.status(daemon) - when :running - $stderr.puts "Daemon already running!" - return - when :stopped - # We are good to go... - else - $stderr.puts "Daemon in unknown state! Will clear previous state and continue." - status(daemon) - PidFile.clear(daemon) - end + # This module contains functionality related to starting and stopping the daemon, and code for processing command line input. + module Controller + # This function is called from the daemon executable. It processes ARGV and checks whether the user is asking for + # <tt>start</tt>, <tt>stop</tt>, <tt>restart</tt> or <tt>status</tt>. + def self.daemonize(daemon) + #puts "Running in #{WorkingDirectory}, logs in #{LogDirectory}" + case !ARGV.empty? && ARGV[0] + when 'start' + start(daemon) + status(daemon) + when 'stop' + stop(daemon) + status(daemon) + PidFile.cleanup(daemon) + when 'restart' + stop(daemon) + PidFile.cleanup(daemon) + start(daemon) + status(daemon) + when 'status' + status(daemon) + else + puts "Invalid command. Please specify start, restart, stop or status." + exit + end + end - daemon.prefork - daemon.mark_err_log + # This function starts the supplied daemon + def self.start(daemon) + puts "Starting daemon..." - fork do - Process.setsid - exit if fork + case PidFile.status(daemon) + when :running + $stderr.puts "Daemon already running!" + return + when :stopped + # We are good to go... + else + $stderr.puts "Daemon in unknown state! Will clear previous state and continue." + status(daemon) + PidFile.clear(daemon) + end - PidFile.store(daemon, Process.pid) + daemon.prefork + daemon.mark_err_log - File.umask 0000 - Dir.chdir daemon.working_directory + fork do + Process.setsid + exit if fork - $stdin.reopen "/dev/null" - $stdout.reopen daemon.log_fn, "a" - $stderr.reopen daemon.err_fn, "a" + PidFile.store(daemon, Process.pid) - main = Thread.new do - begin - daemon.run - rescue - $stderr.puts "=== Daemon Exception Backtrace @ #{Time.now.to_s} ===" - $stderr.puts "#{$!.class}: #{$!.message}" - $!.backtrace.each { |at| $stderr.puts at } - $stderr.puts "=== Daemon Crashed ===" - - $stderr.flush - end - end + File.umask 0000 + Dir.chdir daemon.working_directory - trap("INT") do - daemon.shutdown - main.exit + $stdin.reopen "/dev/null" + $stdout.reopen daemon.log_fn, "a" + $stdout.sync = true + + $stderr.reopen daemon.err_fn, "a" + $stderr.sync = true + + begin + error = nil + + main = Thread.new do + begin + daemon.run + rescue + error = $! + end + end + + trap("INT") do + begin + daemon.shutdown + main.exit + rescue + error = $! + end + end + + trap("TERM") do + exit! + end + + main.join + + raise error if error + rescue + $stderr.puts "=== Daemon Exception Backtrace @ #{Time.now.to_s} ===" + $stderr.puts "#{$!.class}: #{$!.message}" + $!.backtrace.each { |at| $stderr.puts at } + $stderr.puts "=== Daemon Crashed ===" + $stderr.flush + ensure + $stderr.puts "=== Daemon Stopping @ #{Time.now.to_s} ===" + $stderr.flush end + end - trap("TERM") do - exit! - end + puts "Waiting for daemon to start..." + sleep 0.1 + timer = TIMEOUT + pid = PidFile.recall(daemon) - main.join - end + while pid == nil and timer > 0 + # Wait a moment for the forking to finish... + puts "Waiting for daemon to start (#{timer}/#{TIMEOUT})" + sleep 1 - puts "Waiting for daemon to start..." - sleep 0.1 - timer = TIMEOUT - pid = PidFile.recall(daemon) - - while pid == nil and timer > 0 - # Wait a moment for the forking to finish... - puts "Waiting for daemon to start (#{timer}/#{TIMEOUT})" - sleep 1 - - # If the daemon has crashed, it is never going to start... - break if daemon.crashed? - - pid = PidFile.recall(daemon) - - timer -= 1 - end - end + # If the daemon has crashed, it is never going to start... + break if daemon.crashed? - # Prints out the status of the daemon - def self.status(daemon) - case PidFile.status(daemon) - when :running - puts "Daemon status: running pid=#{PidFile.recall(daemon)}" - when :unknown - if daemon.crashed? - puts "Daemon status: crashed" - - $stdout.flush - daemon.tail_err_log($stderr) - else - puts "Daemon status: unknown" - end - when :stopped - puts "Daemon status: stopped" - end - end + pid = PidFile.recall(daemon) - # Stops the daemon process. - def self.stop(daemon) - puts "Stopping daemon..." - - # Check if the pid file exists... - if !File.file?(daemon.pid_fn) - puts "Pid file not found. Is the daemon running?" - return - end + timer -= 1 + end + end - pid = PidFile.recall(daemon) + # Prints out the status of the daemon + def self.status(daemon) + case PidFile.status(daemon) + when :running + puts "Daemon status: running pid=#{PidFile.recall(daemon)}" + when :unknown + if daemon.crashed? + puts "Daemon status: crashed" - # Check if the daemon is already stopped... - unless PidFile.running(daemon) - puts "Pid #{pid} is not running. Has daemon crashed?" - return - end + $stdout.flush + daemon.tail_err_log($stderr) + else + puts "Daemon status: unknown" + end + when :stopped + puts "Daemon status: stopped" + end + end - pid = PidFile.recall(daemon) - Process.kill("INT", pid) - sleep 0.1 - - # Kill/Term loop - if the daemon didn't die easily, shoot - # it a few more times. - attempts = 5 - while PidFile.running(daemon) and attempts > 0 - sig = (attempts < 2) ? "KILL" : "TERM" - - puts "Sending #{sig} to pid #{pid}..." - Process.kill(sig, pid) - - sleep 1 unless first - attempts -= 1 - end - - # If after doing our best the daemon is still running (pretty odd)... - if PidFile.running(daemon) - puts "Daemon appears to be still running!" - return - end - - # Otherwise the daemon has been stopped. - PidFile.clear(daemon) - end - end - end -end \ No newline at end of file + # Stops the daemon process. + def self.stop(daemon) + puts "Stopping daemon..." + + # Check if the pid file exists... + if !File.file?(daemon.pid_fn) + puts "Pid file not found. Is the daemon running?" + return + end + + pid = PidFile.recall(daemon) + + # Check if the daemon is already stopped... + unless PidFile.running(daemon) + puts "Pid #{pid} is not running. Has daemon crashed?" + return + end + + pid = PidFile.recall(daemon) + Process.kill("INT", pid) + sleep 0.1 + + # Kill/Term loop - if the daemon didn't die easily, shoot + # it a few more times. + attempts = 5 + while PidFile.running(daemon) and attempts > 0 + sig = (attempts < 2) ? "KILL" : "TERM" + + puts "Sending #{sig} to pid #{pid}..." + Process.kill(sig, pid) + + sleep 1 + attempts -= 1 + end + + # If after doing our best the daemon is still running (pretty odd)... + if PidFile.running(daemon) + puts "Daemon appears to be still running!" + return + end + + # Otherwise the daemon has been stopped. + PidFile.clear(daemon) + end + end + end +end