Простой unix/linux дэмон на Python

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys, os, time, atexit
  5. from signal import SIGTERM
  6.  
  7. class Daemon:
  8.     """
  9.     Родительский класс дэмона
  10.  
  11.     Использование: создайте подкласс и переопределите метод run()
  12.     """
  13.     def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
  14.         self.stdin = stdin
  15.         self.stdout = stdout
  16.         self.stderr = stderr
  17.         self.pidfile = pidfile
  18.  
  19.     def daemonize(self):
  20.         """
  21.         UNIX double-fork magic, смотрите подробности сдесь Stevens' "Advanced
  22.         Programming in the UNIX Environment" (ISBN 0201563177)
  23.         http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16      """
  24.         try:
  25.             pid = os.fork()
  26.             if pid > 0:
  27.                 sys.exit(0)
  28.         except OSError, e:
  29.             sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
  30.             sys.exit(1)
  31.  
  32.         os.chdir("/")
  33.         os.setsid()
  34.         os.umask(0)
  35.  
  36.         # делаем второй fork
  37.         try:
  38.             pid = os.fork()
  39.             if pid > 0:
  40.                 sys.exit(0)
  41.         except OSError, e:
  42.             sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
  43.             sys.exit(1)
  44.  
  45.         # перенаправление стдн ввода/вывода
  46.         sys.stdout.flush()
  47.         sys.stderr.flush()
  48.         si = file(self.stdin, 'r')
  49.         so = file(self.stdout, 'a+')
  50.         se = file(self.stderr, 'a+', 0)
  51.         os.dup2(si.fileno(), sys.stdin.fileno())
  52.         os.dup2(so.fileno(), sys.stdout.fileno())
  53.         os.dup2(se.fileno(), sys.stderr.fileno())
  54.  
  55.         # записываем pidfile
  56.         atexit.register(self.delpid)
  57.         pid = str(os.getpid())
  58.         file(self.pidfile,'w+').write("%s\n" % pid)
  59.  
  60.     def delpid(self):
  61.         os.remove(self.pidfile)
  62.  
  63.     def start(self):
  64.         """
  65.         Запуск дэмона
  66.         """
  67.         # Проверяем pidfile, чтоб узнать не запущен ли уже процесс
  68.         try:
  69.             pf = file(self.pidfile,'r')
  70.             pid = int(pf.read().strip())
  71.             pf.close()
  72.         except IOError:
  73.             pid = None
  74.  
  75.         if pid:
  76.             message = "pidfile %s already exist. Daemon already running?\n"
  77.             sys.stderr.write(message % self.pidfile)
  78.             sys.exit(1)
  79.  
  80.         # Запуск дэмона
  81.         self.daemonize()
  82.         self.run()
  83.  
  84.     def stop(self):
  85.         """
  86.         Остановка дэмона
  87.         """
  88.         # Берем pid из pidfile
  89.         try:
  90.             pf = file(self.pidfile,'r')
  91.             pid = int(pf.read().strip())
  92.             pf.close()
  93.         except IOError:
  94.             pid = None
  95.  
  96.         if not pid:
  97.             message = "pidfile %s does not exist. Daemon not running?\n"
  98.             sys.stderr.write(message % sфelf.pidfile)
  99.             return # не считается ошибкой при перезапуске
  100.  
  101.         # Убиваем процесс дэмона
  102.         try:
  103.             while 1:
  104.                 os.kill(pid, SIGTERM)
  105.                 time.sleep(0.1)
  106.         except OSError, err:
  107.             err = str(err)
  108.             if err.find("No such process") > 0:
  109.                 if os.path.exists(self.pidfile):
  110.                     os.remove(self.pidfile)
  111.             else:
  112.                 print str(err)
  113.                 sys.exit(1)
  114.  
  115.     def restart(self):
  116.         """
  117.         Перезапуск дэмона
  118.         """
  119.         self.stop()
  120.         self.start()
  121.  
  122.     def run(self):
  123.         """
  124.         Вы должны переопределить данный метод в подклассе. Он должен быть вызван
  125.         после вызова метода daemonize() в методе start().
  126.         """
А вот пример реализации. Просто вызовите этот скрипт с командой start, stop или restart в качестве первого аргумента.
#!/usr/bin/env python
 
import sys, time
from daemon import Daemon
 
class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(1)
 
if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)

Реклама

Мы в соцсетях

tw tg yt gt