Creating a Daemon with Python: Page 2

(Page 2 of 2)

A Good Candidate for Daemonization?

So, why would you want to cause your Python code to daemonize itself?

In general, if you have any code that you want to run for a long time in the background with no user interaction, it is a good candidate for daemonization. You may be wondering, "Why not just use the ampersand (&) like you showed a few examples back?" If you do that, you're not totally guaranteed that logging out won't kill that process.

As an example of daemon processes that you may find yourself in need of writing one day, I've written some system monitoring utilities that need to check different servers and processes on various intervals. I wanted these system monitoring utilities to run indefinitely in the background and they need no user interaction, so they were a good candidate to let them be daemonized. They are, in fact, running at this very moment monitoring some of my production systems.

Here is a small piece of code that uses the daemonize() function from the previous example.

#!/usr/bin/env python

import daemonize
import time
import logging
import os

curr_dir = os.getcwd()
logfile = os.path.join(curr_dir, 'test_daemon.log')
logging.basicConfig(filename=logfile, level=logging.DEBUG, 
        format="%(asctime)s [%(levelname)s] %(message)s")

daemonize.daemonize()

pid_fn = '/var/run/lighttpd.pid'

logging.info('starting')
logging.debug('current directory is %s' % os.getcwd())

while True:
    try:
        pidfile = open(pid_fn)
        pid = int(pidfile.read())
        pidfile.close()
        logging.debug('got pid %s for %s' % (pid, pid_fn))
    except IOError:
        logging.warn('IOError on pidfile open')
        time.sleep(60)
        continue
    except ValueError:
        logging.warn('ValueError on pidfile open')
        time.sleep(60)
        continue
    try:
        stat_fn = os.path.join('/proc', str(pid), 'status')
        logging.debug('opening file %s' % stat_fn)
        stat_file = open(stat_fn, 'r')
        for line in stat_file:
            line = line.strip()
            if line.startswith('VmRSS'):
                logging.info(line)
                break
        stat_file.close()
        time.sleep(60)
    except IOError:
        logging.warn('IOError on statfile open')
        time.sleep(60)
        continue

The purpose of this script is to log the memory usage of the lighttpd web server once every minute. This script tries to open the lighttpd pidfile (/var/run/lighttpd.pid) to see what process ID lighttpd has. Then, it opens /proc/{{pid}}/status, where {{pid}} is the process ID of the lighttpd process. (Files in /proc contain tons of system and process-specific information.)

The script then iterates over each line of the status file and logs the first line that starts with the text string "VmRSS". The "VmRSS" line in the status file shows the amount of memory the process is actively using. The script keeps looping over these steps until it is explicitly killed or it hits an exception I didn't plan for.

Here is some of the output from running the script:

2008-11-18 05:44:24,627 [INFO] starting
2008-11-18 05:44:24,628 [DEBUG] current directory is /
2008-11-18 05:44:24,631 [DEBUG] got pid 13291 for /var/run/lighttpd.pid
2008-11-18 05:44:24,631 [DEBUG] opening file /proc/13291/status
2008-11-18 05:44:24,631 [INFO] VmRSS:       1924 kB
2008-11-18 05:45:24,631 [DEBUG] got pid 13291 for /var/run/lighttpd.pid
2008-11-18 05:45:24,632 [DEBUG] opening file /proc/13291/status
2008-11-18 05:45:24,632 [INFO] VmRSS:       1924 kB

Notice that the current directory is "/". The daemonize() function changed the script's working directory there as part of the process. I only included two iterations of the loop, but you can see that it ran at 05:44:24, slept for 60 seconds, then ran again at 05:45:24.

Daemonizing a process is something you probably don't need to do every day. But if you have a need to kick off a process and have it run indefinitely in the background, this approach could prove useful to you.

Also by Jeremy M. Jones:

Building Command Line Utilities with Python

This article was first published on EnterpriseITPlanet.com.


Page 2 of 2

Previous Page
1 2
 





0 Comments (click to add your comment)
Comment and Contribute

 


(Maximum characters: 1200). You have characters left.