""" The following code describes a class used to daemonize a specific process, by subclassing daemon class. """ import sys import os import time import atexit import signal import subprocess import fcntl class daemon: """ Main class used to daemonize a process. """ def __init__(self, pidfile, streams = None, uid = None): self.pidfile = pidfile self.streams = streams if streams else {} self._set_uid = uid def delpid(self): os.remove(self.pidfile) def daemonize(self): """ Daemonize ourselves. """ try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as err: sys.stderr.write('fork #1 failed: {0}\n'.format(err)) sys.exit(1) os.chdir('/') os.setsid() os.umask(0) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as err: sys.stderr.write('fork #2 failed: {0}\n'.format(err)) sys.exit(1) sys.stdout.flush() sys.stderr.flush() if self.streams: stream_input = open(self.streams.get('stdin', os.devnull), 'r') stream_output = open(self.streams.get('stdout', os.devnull), 'a') stream_error = open(self.streams.get('stderr', os.devnull), 'a') else: stream_input = open(os.devnull, 'r') stream_output = open(os.devnull, 'a') stream_error = open(os.devnull, 'a') os.dup2(stream_input.fileno(), sys.stdin.fileno()) os.dup2(stream_output.fileno(), sys.stdout.fileno()) os.dup2(stream_error.fileno(), sys.stderr.fileno()) atexit.register(self.delpid) pid = str(os.getpid()) with open(self.pidfile, 'w+') as stream: stream.write(pid + '\n') def start(self): """ Start our process. Fails if the the pid from pidfile already exists. """ try: with open(self.pidfile,'r') as stream: fcntl.flock(stream.fileno(), fcntl.LOCK_EX) pid = None try: pid = int(stream.read().strip()) except Exception: pass if pid: exists = self.exists_pid(pid) if exists: message = "pidfile {0} already exist. " + \ "Daemon already running?\n" sys.stderr.write(message.format(self.pidfile)) self.close_handlers(sys) sys.exit(1) except IOError: pass # if it reaches this place then the file does not exists self.daemonize() self.run() # The following reproduces the bug class daemon_subclass(daemon): def run(self): import collections import pickle import sys klas = collections.namedtuple('t', 'a') # This works: globals()[klas.__name__] = klas uple = klas(1) print(pickle.dumps(uple)) # the result will be in out if __name__ == '__main__': d = daemon_subclass("pidfile", {"stdout":"C:\\out", "stderr":"C:\\err"}) d.start()