# -*- coding: utf-8 -*- import os import sys import time import atexit import signal from demeter.core import * class Daemon(object): name = 'demeter' def __init__(self, key='daemon', path='/tmp/', stdin='/dev/null', stdout=True, stderr=True): self.key = key self.path = path + self.name + '_' + key + '/' File.mkdir(self.path) if stdout == False: stdout = '/dev/null' else: stdout = self.path + 'out.log' if stderr == False: stderr = '/dev/null' else: stdout = self.path + 'err.log' self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pid = self.path + self.key + '.pid' def daemonize(self): if os.path.exists(self.pid): raise RuntimeError('Already running.') # First fork (detaches from parent) try: if os.fork() > 0: raise SystemExit(0) except OSError as e: raise RuntimeError('fork #1 faild: {0} ({1})\n'.format(e.errno, e.strerror)) os.chdir('/') os.setsid() os.umask(0o22) # Second fork (relinquish session leadership) try: if os.fork() > 0: raise SystemExit(0) except OSError as e: raise RuntimeError('fork #2 faild: {0} ({1})\n'.format(e.errno, e.strerror)) # Flush I/O buffers sys.stdout.flush() sys.stderr.flush() # Replace file descriptors for stdin, stdout, and stderr with open(self.stdin, 'rb', 0) as f: os.dup2(f.fileno(), sys.stdin.fileno()) with open(self.stdout, 'ab', 0) as f: os.dup2(f.fileno(), sys.stdout.fileno()) with open(self.stderr, 'ab', 0) as f: os.dup2(f.fileno(), sys.stderr.fileno()) # Write the PID file with open(self.pid, 'w') as f: print(os.getpid(), file=f) # Arrange to have the PID file removed on exit/signal atexit.register(lambda: File.remove(self.pid)) signal.signal(signal.SIGTERM, self.__sigterm_handler) # Signal handler for termination (required) @staticmethod def __sigterm_handler(signo, frame): raise SystemExit(1) def start(self): try: self.daemonize() except RuntimeError as e: print(e, file=sys.stderr) raise SystemExit(1) self.run() def stop(self): try: if File.exists(self.pid): with open(self.pid) as f: os.kill(int(f.read()), signal.SIGTERM) else: print('Not running.', file=sys.stderr) raise SystemExit(1) except OSError as e: if 'No such process' in str(e) and File.exists(self.pid): File.remove(self.pid) def restart(self): self.stop() self.start() def run(self): pass