lib/daemons/monitor.rb
require 'daemons/exceptions'
module Daemons
require 'daemons/daemonize'
class Monitor
def self.find(dir, app_name)
pid = PidFile.find_files(dir, app_name, false)[0]
if pid
pid = PidFile.existing(pid)
unless PidFile.running?(pid.pid)
begin; pid.cleanup; rescue ::Exception; end
return
end
monitor = allocate
monitor.instance_variable_set(:@pid, pid)
return monitor
end
nil
end
def initialize(an_app)
@app = an_app
@app_name = an_app.group.app_name + '_monitor'
if an_app.pidfile_dir
@pid = PidFile.new(an_app.pidfile_dir, @app_name, false)
else
@pid = PidMem.new
end
end
def watch(application_group)
sleep(5)
loop do
application_group.applications.each do |a|
unless a.running?
a.zap!
sleep(1)
Process.detach(fork { a.start(restart = true) })
sleep(5)
end
end
sleep(30)
end
end
private :watch
def start_with_pidfile(application_group)
fork do
Daemonize.daemonize(nil, @app_name)
begin
@pid.pid = Process.pid
watch(application_group)
rescue ::Exception => e
begin
File.open(@app.logfile, 'a') do |f|
f.puts Time.now
f.puts e
f.puts e.backtrace.inspect
end
ensure
begin; @pid.cleanup; rescue ::Exception; end
exit!
end
end
end
end
private :start_with_pidfile
def start_without_pidfile(application_group)
Thread.new { watch(application_group) }
end
private :start_without_pidfile
def start(application_group)
return if application_group.applications.empty?
if @pid.kind_of?(PidFile)
start_with_pidfile(application_group)
else
start_without_pidfile(application_group)
end
end
def stop
begin
pid = @pid.pid
Process.kill(Application::SIGNAL, pid)
Timeout.timeout(5, TimeoutError) do
while Pid.running?(pid)
sleep(0.1)
end
end
rescue ::Exception => e
puts "exception while trying to stop monitor process #{pid}: #{e}"
puts 'deleting pid-file.'
end
# We try to remove the pid-files by ourselves, in case the monitor
# didn't clean it up.
begin; @pid.zap; rescue ::Exception; end
end
end
end