Пишем daemon на Python
Нужно было написать демона для одного проекта. Чтобы себе на будущее жизнь облегчить — написал модуль. Возможно еще кому-нибудь понадобится.
Копируем код, приведенный ниже и сохраняем под именем daemon.py
# -*- coding: utf8 -*-
__author__ = "Yaroslav Berezhinskiy"
__copyright__ = "Copyright (C) 2011 Yaroslav Berezhinskiy"
import os
import atexit
import sys
import time
from signal import SIGTERM
#===========================================================================
# "Итерация свойственна человеку, рекурсия божественна."
# Видно, у Б-га стек длинный. А мы останемся людьми.
#===========================================================================
class Daemon():
pidfile = 'pidfile.pid'
stdin='/dev/null'
stdout='/dev/null'
def daemonize(self):
pid = os.fork()
if pid == 0:
os.setsid()
pid = os.fork()
if pid == 0:
os.chdir(".")
os.umask(0)
else:
sys.exit(0)
else:
sys.exit(0)
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)
return pid
def descriptors(self):
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
def delpid(self):
os.remove(self.pidfile)
def start(self,interactive=False):
if interactive:
print "Starting program in interactive mode"
self.run()
return
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid:
message = "Daemon already running? (pid=%s)\n"
sys.stderr.write(message % pid)
sys.exit(1)
pid = self.daemonize()
print "Starting daemon."
self.descriptors()
self.run()
def stop(self):
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if not pid:
message = "Daemon not running? (check %s)\n"
sys.stderr.write(message % self.pidfile)
return
print "Stopping daemon.\nWaiting for PID: %s" % pid
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)
def restart(self):
self.stop()
self.start()
def run(self):
print >> sys.stderr, "ERROR: Daemon not started\nYou need to override run() method in your subclass!"
sys.exit(1)
Дальше нам нужно подключить модуль, написать подкласс для Daemon() и переопределить в нем метод run().
Пример рабочего кода:
#!/usr/bin/env python
# -*- coding: utf8 -*-
import sys
import time
import daemon
class MyDaemon(daemon.Daemon):
def __init__(self):
#---------------------------- Override default PID file in Daemon() class
daemon.Daemon.pidfile = "my_pidfile.pid"
def run(self):
while 1:
time.sleep(1)
my_daemon = MyDaemon()
if len(sys.argv) >= 2:
if 'start' == sys.argv[1]:
my_daemon.start()
elif 'stop' == sys.argv[1]:
my_daemon.stop()
elif 'restart' == sys.argv[1]:
my_daemon.restart()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
PROFIT
Также есть поддержка работы в интерактивном режиме. При передаче значения interactive=True в метод start(), модуль не будет форкать процесс и уводить его в фон, что может быть весьма полезно при отладке кода:
my_daemon.start(interactive=True)
Опубликовано 16.10.2011 в 19:45 · Автор Berezhinskiy · Ссылка
Рубрики: Programming, python · Теги: daemon, fork, python, демон на питоне
Рубрики: Programming, python · Теги: daemon, fork, python, демон на питоне

27 января 2012 в 12:37
· Ссылка
Очень полезно, спасибо, новичок в деле написания демонов помогло без лишних телодвижений