Skip to content

Managing Python daemon processes with Bash

2010 October 29
tags: ,
by Tedb0t

Usually if you want to kill some processes they have to have unique names or you have to know their process IDs.  Lately I’ve had a group of python daemon scripts that need to be restarted occasionally, so instead of looking at a list, finding the pids and killing them manually, here’s an  approach that uses PID files to keep note of the process’ ID, so you can just reference the file.  There’s a Bash script and a snippet that should be at the beginning of the python scripts.  Right now this is in conjunction with monit, which will start the scripts if they’re not running.  Monit can restart them for you, too, but apparently I was feeling masochistic this day.  This is adapted from original code by Brian House (thanks Brian!)

restart.sh:

#!/bin/bash

PROCESS_PATH="run/"
PROCESS_LIST=( "render_city.pid" "render_cards.pid" "email_sender.pid" "sms_sender.pid" )

function killProcess {
    echo "killProcess $1"
    PIDFILE=$PROCESS_PATH$1
    PID=0
    if [ -e $PIDFILE ]; then
        PID=`cat $PIDFILE`
        if [ "x" == "x$PID" ]; then
            PID=0
        fi
    fi
    if [ "$PID" != "0" ]; then
        echo "--> Killing current process $PID..."
        sudo kill $PID
    else
        echo '--> Nothing to kill.'
    fi
}

if [ ! -z "$1" ]; then
    if [ $1 == "all" ]; then
        echo "*** Killing all"
        chmod +x daemons/*  # since svn strips permissions, always make sure they're executable

        ELEMENTS=${#PROCESS_LIST[@]}
        for (( i=0; i<$ELEMENTS; i++)); do
            killProcess ${PROCESS_LIST[${i}]}
        done
    fi
fi

Here’s a python function that manages the PID file (written by Brian, goes in a util.py module):

def confirm_pid(run_folder):
    import sys, os, signal, __main__
    name = prefix('.', os.path.basename(__main__.__file__))
    log.info("Attempting to launch daemon %s..." % name)
    pid = str(os.getpid())
    pidfile = "%s%s.pid" % (run_folder, name)
    if os.path.isfile(pidfile):
        old_pid = open(pidfile).read()
        log.warning("--> pidfile already exists for %s, attempting to kill process..." % old_pid)
        try:
            result = os.kill(int(old_pid), signal.SIGKILL)
        except OSError, e:
            if e.args[0] == 3:
                log.warning("--> no process with pid %s" % old_pid)
            else:
                log.error(e)
                exit()
        else:
            log.info("--> killed process %s" % old_pid)
        try:
            os.unlink(pidfile)
        except OSError, e:
            log.error("--> could not remove pidfile, %s" % pidfile)
            exit()
    open(pidfile, 'w').write(pid)
    log.info("--> launched with pid %s" % pid)

…and the snippet that goes at the top of the daemon:

import sys, os
sys.path.append(os.path.dirname(__file__) + "/../")
util.confirm_pid(os.path.dirname(__file__) + "/../run/")

Related Posts:


Comments are closed.