ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: Creating a daemon the Python way
Submitter: Chad J. Schroeder (other recipes)
Last Updated: 2005/10/03
Version no: 1.5
Category: Threads

 

4 stars 9 vote(s)


Description:

The Python way to detach a process from the controlling terminal and run it in the
background as a daemon.

Source: Text Source

"""Disk And Execution MONitor (Daemon)

Configurable daemon behaviors:

   1.) The current working directory set to the "/" directory.
   2.) The current file creation mode mask set to 0.
   3.) Close all open files (1024). 
   4.) Redirect standard I/O streams to "/dev/null".

A failed call to fork() now raises an exception.

References:
   1) Advanced Programming in the Unix Environment: W. Richard Stevens
   2) Unix Programming Frequently Asked Questions:
         http://www.erlenstar.demon.co.uk/unix/faq_toc.html
"""

__author__ = "Chad J. Schroeder"
__copyright__ = "Copyright (C) 2005 Chad J. Schroeder"

__revision__ = "$Id$"
__version__ = "0.2"

# Standard Python modules.
import os               # Miscellaneous OS interfaces.
import sys              # System-specific parameters and functions.

# Default daemon parameters.
# File mode creation mask of the daemon.
UMASK = 0

# Default working directory for the daemon.
WORKDIR = "/"

# Default maximum for the number of available file descriptors.
MAXFD = 1024

# The standard I/O file descriptors are redirected to /dev/null by default.
if (hasattr(os, "devnull")):
   REDIRECT_TO = os.devnull
else:
   REDIRECT_TO = "/dev/null"

def createDaemon():
   """Detach a process from the controlling terminal and run it in the
   background as a daemon.
   """

   try:
      # Fork a child process so the parent can exit.  This returns control to
      # the command-line or shell.  It also guarantees that the child will not
      # be a process group leader, since the child receives a new process ID
      # and inherits the parent's process group ID.  This step is required
      # to insure that the next call to os.setsid is successful.
      pid = os.fork()
   except OSError, e:
      raise Exception, "%s [%d]" % (e.strerror, e.errno)

   if (pid == 0):	# The first child.
      # To become the session leader of this new session and the process group
      # leader of the new process group, we call os.setsid().  The process is
      # also guaranteed not to have a controlling terminal.
      os.setsid()

      # Is ignoring SIGHUP necessary?
      #
      # It's often suggested that the SIGHUP signal should be ignored before
      # the second fork to avoid premature termination of the process.  The
      # reason is that when the first child terminates, all processes, e.g.
      # the second child, in the orphaned group will be sent a SIGHUP.
      #
      # "However, as part of the session management system, there are exactly
      # two cases where SIGHUP is sent on the death of a process:
      #
      #   1) When the process that dies is the session leader of a session that
      #      is attached to a terminal device, SIGHUP is sent to all processes
      #      in the foreground process group of that terminal device.
      #   2) When the death of a process causes a process group to become
      #      orphaned, and one or more processes in the orphaned group are
      #      stopped, then SIGHUP and SIGCONT are sent to all members of the
      #      orphaned group." [2]
      #
      # The first case can be ignored since the child is guaranteed not to have
      # a controlling terminal.  The second case isn't so easy to dismiss.
      # The process group is orphaned when the first child terminates and
      # POSIX.1 requires that every STOPPED process in an orphaned process
      # group be sent a SIGHUP signal followed by a SIGCONT signal.  Since the
      # second child is not STOPPED though, we can safely forego ignoring the
      # SIGHUP signal.  In any case, there are no ill-effects if it is ignored.
      #
      # import signal           # Set handlers for asynchronous events.
      # signal.signal(signal.SIGHUP, signal.SIG_IGN)

      try:
         # Fork a second child and exit immediately to prevent zombies.  This
         # causes the second child process to be orphaned, making the init
         # process responsible for its cleanup.  And, since the first child is
         # a session leader without a controlling terminal, it's possible for
         # it to acquire one by opening a terminal in the future (System V-
         # based systems).  This second fork guarantees that the child is no
         # longer a session leader, preventing the daemon from ever acquiring
         # a controlling terminal.
         pid = os.fork()	# Fork a second child.
      except OSError, e:
         raise Exception, "%s [%d]" % (e.strerror, e.errno)

      if (pid == 0):	# The second child.
         # Since the current working directory may be a mounted filesystem, we
         # avoid the issue of not being able to unmount the filesystem at
         # shutdown time by changing it to the root directory.
         os.chdir(WORKDIR)
         # We probably don't want the file mode creation mask inherited from
         # the parent, so we give the child complete control over permissions.
         os.umask(UMASK)
      else:
         # exit() or _exit()?  See below.
         os._exit(0)	# Exit parent (the first child) of the second child.
   else:
      # exit() or _exit()?
      # _exit is like exit(), but it doesn't call any functions registered
      # with atexit (and on_exit) or any registered signal handlers.  It also
      # closes any open file descriptors.  Using exit() may cause all stdio
      # streams to be flushed twice and any temporary files may be unexpectedly
      # removed.  It's therefore recommended that child branches of a fork()
      # and the parent branch(es) of a daemon use _exit().
      os._exit(0)	# Exit parent of the first child.

   # Close all open file descriptors.  This prevents the child from keeping
   # open any file descriptors inherited from the parent.  There is a variety
   # of methods to accomplish this task.  Three are listed below.
   #
   # Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
   # number of open file descriptors to close.  If it doesn't exists, use
   # the default value (configurable).
   #
   # try:
   #    maxfd = os.sysconf("SC_OPEN_MAX")
   # except (AttributeError, ValueError):
   #    maxfd = MAXFD
   #
   # OR
   #
   # if (os.sysconf_names.has_key("SC_OPEN_MAX")):
   #    maxfd = os.sysconf("SC_OPEN_MAX")
   # else:
   #    maxfd = MAXFD
   #
   # OR
   #
   # Use the getrlimit method to retrieve the maximum file descriptor number
   # that can be opened by this process.  If there is not limit on the
   # resource, use the default value.
   #
   import resource		# Resource usage information.
   maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
   if (maxfd == resource.RLIM_INFINITY):
      maxfd = MAXFD
  
   # Iterate through and close all file descriptors.
   for fd in range(0, maxfd):
      try:
         os.close(fd)
      except OSError:	# ERROR, fd wasn't open to begin with (ignored)
         pass

   # Redirect the standard I/O file descriptors to the specified file.  Since
   # the daemon has no controlling terminal, most daemons redirect stdin,
   # stdout, and stderr to /dev/null.  This is done to prevent side-effects
   # from reads and writes to the standard I/O file descriptors.

   # This call to open is guaranteed to return the lowest file descriptor,
   # which will be 0 (stdin), since it was closed above.
   os.open(REDIRECT_TO, os.O_RDWR)	# standard input (0)

   # Duplicate standard input to standard output and standard error.
   os.dup2(0, 1)			# standard output (1)
   os.dup2(0, 2)			# standard error (2)

   return(0)

if __name__ == "__main__":

   retCode = createDaemon()

   # The code, as is, will create a new file in the root directory, when
   # executed with superuser privileges.  The file will contain the following
   # daemon related process parameters: return code, process ID, parent
   # process group ID, session ID, user ID, effective user ID, real group ID,
   # and the effective group ID.  Notice the relationship between the daemon's 
   # process ID, process group ID, and its parent's process ID.

   procParams = """
   return code = %s
   process ID = %s
   parent process ID = %s
   process group ID = %s
   session ID = %s
   user ID = %s
   effective user ID = %s
   real group ID = %s
   effective group ID = %s
   """ % (retCode, os.getpid(), os.getppid(), os.getpgrp(), os.getsid(0),
   os.getuid(), os.geteuid(), os.getgid(), os.getegid())

   open("createDaemon.log", "w").write(procParams + "\n")

   sys.exit(retCode)

Discussion:

Updated and improved.

This recipe details how to implement/create a daemon in Python. Just call the createDaemon() function and it will daemonize your process. It's well documented and hopefully useful. Any ideas or suggestions are welcome. Enjoy.

References:
1) Advanced Programming in the Unix Environment: W. Richard Stevens
2) Unix Programming Frequently Asked Questions:
http://www.erlenstar.demon.co.uk/unix/faq_toc.html



Add comment

Number of comments: 26

Problem with closing file descriptors, Graham Ashton, 2004/05/08
Nicely documented recipe. But I can't see how opening file descriptors like this would correctly handle stdin, stdout and stderr:

# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY)    # standard input (0)
os.open("/dev/null", os.O_RDWR)      # standard output (1)
os.open("/dev/null", os.O_RDWR)      # standard error (2)
Obviously, you don't really want to close the existing ones, but I once saw a good trick in Python Standard Library (Lundh) for doing a similar thing:
class NullDevice:
    def write(self, s):
        pass
sys.stdin.close()
sys.stdout = NullDevice()
sys.stderr = NullDevice()
I've used that quite a bit, with some success.
Add comment

How it works, Chad J. Schroeder, 2004/05/12

In general, when creating a daemon, you  want to close all file
descriptors inherited  from the parent process.  createDaemon()
closes all file descriptors from 0 to maxfd.  This isn't always
necessary, but it's good practice.
Next, three calls to os.open() are made.  This function returns,
when  successful, the lowest file descriptor not currently open
for  the process.   Since  the  standard  fd's  (0, 1, 2)  were
previously closed,  they're now recreated in the daemon process
with an association to /dev/null rather than the actual standard
I/O streams.

Now, anytime a reference is made to the standard I/O streams in
the daemon process, it's redirected to /dev/null.
As visual proof, try the following.  Modify the os.open() calls
to:

os.open("/testlog", os.O_CREAT|os.O_APPEND|os.O_RDONLY) # stdin 
os.open("/testlog", os.O_CREAT|os.O_APPEND|os.O_RDWR)   # stdout
os.open("/testlog", os.O_CREAT|os.O_APPEND|os.O_RDWR)   # stderr

And add the following to the end of the file:

...

# won't be created and no errors will be reported.
open("createDaemon.log", "w").write("rc: %s; pid: %d; ppid: %d; pgrp: %d\n"%\
   (retCode, os.getpid(), os.getppid(), os.getpgrp()))

sys.stdout.write("test stdout\n")
sys.stdout.flush()
sys.stderr.write("test stderr\n")
sys.stderr.flush()

...

The output contained in /testlog verifies the standard I/O streams,
stdout and stderr, are redirected.
Hope this helps.

Add comment

Problem with closing file descriptors, Graham Ashton, 2004/05/08
Nicely documented recipe. But I can't see how opening file descriptors like this would correctly handle stdin, stdout and stderr:

# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY)    # standard input (0)
os.open("/dev/null", os.O_RDWR)      # standard output (1)
os.open("/dev/null", os.O_RDWR)      # standard error (2)
Obviously, you don't really want to close the existing ones, but I once saw a good trick in Python Standard Library (Lundh) for doing a similar thing:
class NullDevice:
    def write(self, s):
        pass
sys.stdin.close()
sys.stdout = NullDevice()
sys.stderr = NullDevice()
I've used that quite a bit, with some success.
Add comment

Chad J. Schroeder, 2004/05/12

Add comment

How is this better than "&"?, Doug DeCoudras, 2004/06/28
Hi, I'm newish to Python and I'm wondering how this approach to writing a daemon is better than running a Python script in the background (run from a Linux or UNIX command line) as follows? : $ python myPython.py Hi, I'm newish to Python and I'm wondering how this approach to writing a daemon is better than running a Python script in the background (run from a Linux or UNIX command line) as follows? : $ python myPython.py
Add comment

Depends On Use, tuco Leone, 2005/10/08

"How is this better than [background task]?"
For long-running processes that are not tied to a terminal, for example.
Add comment

Why O_RDWR for stdout and stderr, Blair Zajac, 2004/06/30
Good read. One question. Why do you reopen fd's 1 and 2 using O_RDWR instead of O_WRONLY?
Add comment

RE: Why O_RDWR for stdout and stderr, Chad J. Schroeder, 2004/07/06

I guess it's a matter of habit and how I've seen it done in the past.
When programming a daemon in C, I tend to open/create a file descriptor to "/dev/null" (or any file)
[fd = open(DEVNULL, O_RDWR)] with the RDWR flag and then duplicate the standard descriptors:
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
I just carried the idea/style to the pythonized daemon code.

Add comment

The Daemon Process Is Using Most of the CPU, Brad Touesnard, 2004/07/13
First off, this is some great advice for writting daemon applications.

Problem:

I am running a daemon application using your code to convert the process to a daemon. It works great, but shortly after running, it starts to occupy almost all the CPU as if the process is in spinlock. However, the process should be blocking (rather than spinning) as it is waiting to read from a named pipe. Any idea why the process is taking up most of the CPU and how to stop it from doing so? Here's the code after I call the "createDaemon()" function:

# Write process id to a file
fp = open(pid_file, 'w')
fp.write(str(os.getpid()))
fp.close()

fpipe = open(pipe_path, 'r')

while 1:
  log_line = fpipe.readline()

  input_list = log_line.split('\t')

  if len(input_list) < 4:
    continue

  file_path = input_list[4]

  slash_pos1 = file_path.find('/', 1)
  slash_pos2 = file_path.find('/', slash_pos1 + 1)

  homedir_path = file_path[:slash_pos2]
  logs_path = homedir_path + '/logs'

  if debug_on:
    print 'Logging to ' + logs_path

  if os.path.exists(logs_path):
    fp = open(logs_path + '/xferlog', 'a')
    fcntl.lockf(fp, fcntl.LOCK_EX)
    fp.write(log_line)
    fcntl.lockf(fp, fcntl.LOCK_UN)
    fp.close()

fpipe.close()

Add comment

RE: The Daemon Process Is Using Most of the CPU, Chad J. Schroeder, 2004/07/16

My two cents -
It looks like you're creating a busy while loop.  The fpipe.readline()
returns immediately when there is nothing to read, it doesn't block,
creating the busy while loop until there is something to read.  This is why
your CPU usage rises.
You may want to look at using something like select and/or the low level
open, read, and write (and other tools) in the os module.

Add comment

error to syslog, Gijs Molenaar, 2005/06/15
I'm using this code, and it functioning very good. But sometimes (once a week) my application crashes. I tried to try/except everything, but somehow sometimes something goes wrong. I've created a function log(), that I can use for logging. At this moment it sends me an e-mail and writes and entry in syslog. I want to redirect stderr to this function, but the problem is that strerr is a stream, and I don't really know how you can convert this to a log() call. Does anyone has an idea or am I thinking wrong?
Add comment

Gijs Molenaar, 2005/06/15
sorry, the answer is in the code I see now... I feel ashamed. I didn't implement the full code. _and_ I pushed the wrong 'add comment' button. Sorry for wasting time!
Add comment

Gijs Molenaar, 2005/06/15
The answer is quite simpel:

import sys

class LogErr:
    def write(self, data):
        print "log: " + data

t = LogErr()
sys.stderr = t
sys.stderr.write("test stderr\n")
I've put it here, maybe it can be usefull for somebody.
Add comment

Simplify, Neal Becker, 2005/09/14
I don't see why 2 forks are needed. I think all that's needed is: if (os.fork()) == 0: os.setsid() maxfd = os.sysconf("SC_OPEN_MAX") for fd in range(0, maxfd): try: os.close(fd) except OSError: # ERROR (ignore) pass # Redirect the standard file descriptors to /dev/null. os.open("/dev/null", os.O_RDONLY) # standard input (0) os.open("/dev/null", os.O_RDWR) # standard output (1) os.open("/dev/null", os.O_RDWR) # standard error (2) else: sys.exit (0)
Add comment

It always takes two forks to make a daemon. This is tradition., Noah Spurrier, 2005/09/27
Some UNIXes don't require it. It doesn't hurt to do it on all UNIXes. The reason some UNIXes require it is to make sure that the daemon process is NOT a session leader. A session leader process may attempt to aquire a controlling terminal. By definition a daemon does not have a controlling terminal. This is one of the steps that might not be strictly necessary, but it will eliminate one possible source for faults.
Add comment

Depends On Use, tuco Leone, 2005/10/08

"I don't see why 2 forks are needed."
To have a seperate, stand-alone process running that is abandoned by its parent to live its own life without ever knowing if its parant is alive or dead, for example.

Add comment

Benifit To The Parent , tuco Leone, 2005/10/11
And don't forget that the parent process who double-fork()s their daemon child never has to worry about it turning into a Zombie when they die too.
Add comment

Example of usage, jd holt, 2005/11/21
I have tried to implement this but I am having trouble. Here is what I have tried.

#!/usr/bin/env python
import pyDaemon
import time
import sys
import os
pyDaemon.createDaemon()
def logit(self):
        fp = open('test.log','w')
        fp.write('Hello\n')
        fp.close()
while true:
        time.sleep(300)
        logit()

I left the Daemon Code untouched and nothing happens.

Thanks,
         Josh holt

Add comment

Error in your program, Chris Cogdon, 2006/06/12
Because stderr is being redirected to /dev/null, you won't be informed of any errors in your program. In this case, you have 'self' as a parameter to logit, but it's not class member. Just remove 'self' and it should work fine. Also, you might want to use mode "a" rather than "w"; this way you'll see "Hello!" being added every 5 minutes, rather than just one "Hello!"
Add comment

Random file descriptor, francis giraldeau, 2006/06/17
When using the random module after daemonize, then the file description is not accessible anymore, and it produce this error:

Traceback (most recent call last):
File "/usr/share/mille-xterm/lbserver/main.py", line 332, in ?
main()
File "/usr/share/mille-xterm/lbserver/main.py", line 287, in main
random.seed()
File "/usr/lib/python2.4/random.py", line 110, in seed
a = long(_hexlify(_urandom(16)), 16)
File "/usr/lib/python2.4/os.py", line 728, in urandom
bytes += read(_urandomfd, n - len(bytes))
OSError: [Errno 9] Bad file descriptor


Should I preserve file descriptors? I don't see another way to do it. Thanks for any hint,
Francis
Add comment

sasa sasa, 2006/10/06
This is python bug 1177468, it's apparently fixed in python cvs since 4th July 2005 but may not have made it to your distribution yet. Without the fixed os.py, your only option is to leave the file descriptors open.
Add comment

sasa sasa, 2006/11/02
Actually you do need to close 0,1,2 otherwise you won't get any stdout/stderr redirects from the os.open calls.
Add comment

Can't quite get this to work, Brandon Pierce, 2006/11/10

Hello,

I've been testing this with the following code:

#!/usr/bin/python
import pyDaemon
import time

def logit():
	fp = open('test.log','a')
	fp.write('Hello\n')
	fp.close()

pyDaemon.createDaemon()
while 1:
        time.sleep(5)
        logit()

This is basically what one of the other folks earlier was doing.
I have it saves in a file called 'test.py'. I'm new to Python, and have
never done anything with daemons, so I wanted to see how it works.
If I start this using 'python test.py', it seem to start, and I can
see it running as a process, but nothing gets written to the log
file. The file exists and I gave it permissions of 777.
If I comment out the line that executes the createDaemon() function,
it works fine, aside from not being daemonized (naturally). Any ideas? Thanks! Brandon

Add comment

Check /, Lloyd Carothers, 2006/11/21
The daemon code sets the current working dir of the process to /. You're file is either here or you don't have permission to write here. If you're doing serious logging check out syslog. There are some recipes on this site.
Add comment

Handling SIGTERM, greg p, 2007/10/14
How can I make my daemon using this code handle SIGTERM.

See I have it created child processes when it starts up, and when the daemon is shut down, I want it to clean up those child processes. I figured I could put the clean up code in a function.

Here's what I tried so far:

def handle_sigterm():
    """Kill all child processes to clean up."""
    logging.info('handle_sigterm called.')

signal.signal(signal.SIGTERM,handle_sigterm)
But when running $ sudo kill -15 [PID] against it, that function never gets called.
Add comment

Redirecting both stdout and stderr to the same file, Felipe Pereira, 2008/01/24
Here's what I wanted:

* print statements output should go to a logfile (even print >> sys.stderr)
* children (e.g. os.system calls) should output to the same logfile
* without touching daemonize.py code

Here's how I solved.

First of all, I needed to add:
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
To createDaemon() code. Closing underlying C buffers without closing (and thus notifying) sys.std* seems to be bad. There's also another recipe here about this. According to Python docs, if you close sys streams, the associated fd is not really closed. So we still need to close 0,1 and 2 fds.

This was the only change I made to createDaemon(). I think it's not a problem, because I was going to reassign sys.std* afterwards.

Now my code: bla.py
#!/usr/bin/python

import daemon
import os,sys,time

daemon.createDaemon()

sys.stdout.close() #we close /dev/null
sys.stderr.close()

os.close(2) # and associated fd's
os.close(1)

# now we open a new stdout
# * notice that underlying fd is 1
# * bufsize is 1 because we want stdout line buffered (it's my log file)
sys.stdout = open('/tmp/bla','w',1) # redirect stdout
os.dup2(1,2) # fd 2 is now a duplicate of fd 1
sys.stderr = os.fdopen(2,'a',0) # redirect stderr
# from now on sys.stderr appends to fd 2
# * bufsize is 0, I saw this somewhere, I guess no bufferization at all is better for stderr

# now some tests... we want to know if it's bufferized or not
print "stdout"
print >> sys.stderr, "stderr"
os.system("echo stdout-echo") # this is unix only...
os.system("echo stderr-echo > /dev/stderr")
# cat /tmp/bla and check that it's ok; to kill use: pkill -f bla.py
while 1:
        time.sleep(1)

sys.exit(0)
Ps: I had to replace "tumbler" for "aspn" in the URL to comment this!
Ps2: this is for Unix!

Add comment



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. Wrapping template engine ...

4. Assignment in expression

5. SOLVING THE METACLASS ...

6. Povray for python

7. Calling Windows API ...

8. Generic filter logic ...

9. Function Decorators by ...

10. MS SQL Server log monitor




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.