Skip to content

Instantly share code, notes, and snippets.

@tumani1
Created February 4, 2014 11:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tumani1/8802193 to your computer and use it in GitHub Desktop.
Save tumani1/8802193 to your computer and use it in GitHub Desktop.
Fork LightDaemon. Главный процесс ответвляется от консоли и запускает набор задач на исполнение. Запущенный список задач мониторится на живучесть. В случае падения child worker перезапустит его.
module LightDaemon
class Daemon
DEFAULT_PID_FILE = "/tmp/light_daemon.pid"
class << self
def start(obj, options={})
@options = self.parse_options(options)
@pid_file = @options[:pid_file]
if self.get_pid()
raise "The pid file \"#{@pid_file}\" existed already. You need to stop the daemon first."
end
self.new(obj).start()
end
def stop(pid_file=DEFAULT_PID_FILE)
@pid_file = pid_file
if (pid = self.get_pid())
kill_flag = false
begin
Process.kill("TERM", pid)
kill_flag = true
rescue Errno::EPERM
p "No permission to query #{pid}!"
rescue Errno::ESRCH
"#{pid} is NOT running."
kill_flag = true
rescue Exception => e
p "Unable to determine status for #{pid}: #{e.message}"
ensure
if kill_flag
self.clear_pid
end
end
end
end
def get_pid()
return nil unless File.exist?(@pid_file)
begin
result = File.open(@pid_file) {|f| f.read}.to_i
rescue Exception => e
result = nil
end
return result
end
def set_pid(pid)
File.open(@pid_file, 'w') {|f| f.write(pid.to_s)}
end
def clear_pid()
File.unlink(@pid_file)
end
def parse_options(options)
options[:pid_file] ||= DEFAULT_PID_FILE
return options
end
def debugging()
# Not Implemented
end
end
def initialize(obj)
# Make our proccess as daemon
daemonize()
# Set pid in the file for current pid
self.class.set_pid(Process.pid)
# List objects for execute
@obj = (!obj.kind_of?(Array)) ? [obj] : obj
# Starting list pids
@processes = {}
# Flag for child
@is_child = false
# Running flag
@is_ranning_wait_pid = true
# Start execute observer
signal_handling()
end
def process_alive?(pid)
return false unless pid
begin
Process.kill(0, pid)
rescue Errno::EPERM
#p "No permission to query #{pid}!";
rescue Errno::ESRCH
#p "#{pid} is NOT running.";
return false
rescue Exception => e
#p "Unable to determine status for #{pid} : #{e.message}"
end
return true
end
def start()
@obj.each do |obj|
pid = fork do
item.call()
end
@processes.merge!({pid => obj})
end
keep_running()
end
private
def daemonize()
fork && exit
unless Process.setsid
raise 'Can not detach from controlling terminal'
end
trap 'SIGHUP', 'IGNORE'
exit if fork
begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
begin; STDERR.reopen STDOUT; rescue ::Exception; end
STDERR.sync = true
end
def signal_handling()
# Setup variable
$keep_running = true
Signal.trap "TERM" do
unless @is_child
$keep_running = false
@processes.each do |pid, obj|
begin
Process.kill("TERM", pid)
rescue Exception => e
end
end
# wait
sleep(5)
@processes.size.times do
pid, obj = @processes.shift
if process_alive?(pid)
@processes.merge!({pid => obj})
sleep(5)
end
end
@processes.each do |pid, obj|
if process_alive?(pid)
Process.kill(9, pid)
end
end
# Clear pid file
self.class.clear_pid()
end
end
end
def keep_running()
while $keep_running do
wpid, status = Process.wait(-1, Process::WNOHANG)
if @processes.include?(wpid)
obj = @processes[wpid]
@processes.delete(wpid)
pid = fork do
obj.call()
end
@processes.merge!({pid => obj})
end
sleep(5)
end
end
end
end
class Test
def initialize(value)
@value = value
end
def call()
while true do
`echo "process: #{Process.pid} - #{@value}" >> /tmp/my-daemon.txt`
sleep(3)
end
end
end
p "Start task:"
LightDaemon::Daemon.start([Test.new(2), Test.new(1), Test.new(3)])
# p "Is running:"
# AMQP_Daemon::Daemon.process_alive?()
#p "Stop task:"
#AMQP_Daemon::Daemon.stop()
# p "Is running:"
# AMQP_Daemon::Daemon.process_alive?()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment