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/")