How to make a Python script run like a service or daemon in Linux How to make a Python script run like a service or daemon in Linux python python

How to make a Python script run like a service or daemon in Linux


You have two options here.

  1. Make a proper cron job that calls your script. Cron is a common name for a GNU/Linux daemon that periodically launches scripts according to a schedule you set. You add your script into a crontab or place a symlink to it into a special directory and the daemon handles the job of launching it in the background. You can read more at Wikipedia. There is a variety of different cron daemons, but your GNU/Linux system should have it already installed.

  2. Use some kind of python approach (a library, for example) for your script to be able to daemonize itself. Yes, it will require a simple event loop (where your events are timer triggering, possibly, provided by sleep function).

I wouldn't recommend you to choose 2., because you would be, in fact, repeating cron functionality. The Linux system paradigm is to let multiple simple tools interact and solve your problems. Unless there are additional reasons why you should make a daemon (in addition to trigger periodically), choose the other approach.

Also, if you use daemonize with a loop and a crash happens, no one will check the mail after that (as pointed out by Ivan Nevostruev in comments to this answer). While if the script is added as a cron job, it will just trigger again.


Here's a nice class that is taken from here:

#!/usr/bin/env pythonimport sys, os, time, atexitfrom signal import SIGTERMclass Daemon:        """        A generic daemon class.        Usage: subclass the Daemon class and override the run() method        """        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):                self.stdin = stdin                self.stdout = stdout                self.stderr = stderr                self.pidfile = pidfile        def daemonize(self):                """                do the UNIX double-fork magic, see Stevens' "Advanced                Programming in the UNIX Environment" for details (ISBN 0201563177)                http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16                """                try:                        pid = os.fork()                        if pid > 0:                                # exit first parent                                sys.exit(0)                except OSError, e:                        sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))                        sys.exit(1)                # decouple from parent environment                os.chdir("/")                os.setsid()                os.umask(0)                # do second fork                try:                        pid = os.fork()                        if pid > 0:                                # exit from second parent                                sys.exit(0)                except OSError, e:                        sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))                        sys.exit(1)                # redirect standard file descriptors                sys.stdout.flush()                sys.stderr.flush()                si = file(self.stdin, 'r')                so = file(self.stdout, 'a+')                se = file(self.stderr, 'a+', 0)                os.dup2(si.fileno(), sys.stdin.fileno())                os.dup2(so.fileno(), sys.stdout.fileno())                os.dup2(se.fileno(), sys.stderr.fileno())                # write pidfile                atexit.register(self.delpid)                pid = str(os.getpid())                file(self.pidfile,'w+').write("%s\n" % pid)        def delpid(self):                os.remove(self.pidfile)        def start(self):                """                Start the daemon                """                # Check for a pidfile to see if the daemon already runs                try:                        pf = file(self.pidfile,'r')                        pid = int(pf.read().strip())                        pf.close()                except IOError:                        pid = None                if pid:                        message = "pidfile %s already exist. Daemon already running?\n"                        sys.stderr.write(message % self.pidfile)                        sys.exit(1)                # Start the daemon                self.daemonize()                self.run()        def stop(self):                """                Stop the daemon                """                # Get the pid from the pidfile                try:                        pf = file(self.pidfile,'r')                        pid = int(pf.read().strip())                        pf.close()                except IOError:                        pid = None                if not pid:                        message = "pidfile %s does not exist. Daemon not running?\n"                        sys.stderr.write(message % self.pidfile)                        return # not an error in a restart                # Try killing the daemon process                       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):                """                Restart the daemon                """                self.stop()                self.start()        def run(self):                """                You should override this method when you subclass Daemon. It will be called after the process has been                daemonized by start() or restart().                """


You should use the python-daemon library, it takes care of everything.

From PyPI: Library to implement a well-behaved Unix daemon process.