Monday, February 11, 2008

Python script; check running process

If you launch a long running processing, sometimes you don't want to relaunch the script while the other process is still running. There are bash oriented ways of checking for this, but I wanted to make these complicated and use a more robust language. Here is a script to check a PID file, check and grep the 'ps aux' for a particular name and return 0 exit code if the process is not running.

"""
Berlin Brown
Date: 2/2/2008
Copyright: Public Domain

Utility for checking if process is running.

Versions:
Should work with python 2.4+

Use case includes:
* If PID file found, read the contents
* If PID file found or not found, also check the 'ps aux' status of the script
to make sure that the script is not running.

Additional FAQ:
* What if the PID file gets created but does not get removed?
+ In this scenario, we need to issue a 'force' command. But also,
check the running process with the 'ps aux' command.

Script/App Exit Codes:
0 - Pass, sucess
1 - catchall for general errors
3 - Used for botlist purposes

References:
http://docs.python.org/lib/node536.html
"""


__author__ = "Berlin Brown"
__version__ = "0.1"
__copyright__ = "Copyright (c) 2006-2008 Berlin Brown"
__license__ = "Public Domain"

import sys
import os
from subprocess import Popen, call, PIPE

PROC_SCRIPT_NAME = "check_process.py"

SUCCESS_EXIT_CODE=0
ERR_PS_SCRIPT_RUNNING=3
ERR_PID_SCRIPT_RUNNING=4

def check_ps_cmd(script_name):
try:
p1 = Popen(["ps", "aux"], stdout=PIPE)
p2 = Popen(["grep", script_name], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
return output
except Exception, e:
print >>sys.stderr, "Execution failed:", e
return None

def is_pid_running(full_cmd):
try:
p = Popen(full_cmd, shell=True, stdout=PIPE)
output = p.communicate()[0]
if output:
# if something is there then we can return true
return True
except Exception, e:
print >>sys.stderr, "Execution failed:", e
return False
# Final exit
return False

def find_std_output(std_output, script_name):
# split the ps aux output and check the parameters
data = std_output.split()
# first, ignore the current script and eliminate
for i in data:
if i.find(PROC_SCRIPT_NAME) > 0:
return False
# Begin search again, for the target script name
for i in data:
if i.find(script_name) > 0:
return True
return False

def is_script_running(script_name):
res = False
std_output = check_ps_cmd(script_name)
if std_output:
std_output = std_output.split('\n')
for curline in std_output:
res = find_std_output(curline, script_name)
return res

def launch_process(full_cmd):
try:
retcode = call(full_cmd, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
return retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
return -1

def main(args):
if len(args) < 3:
return -1
else:
# Arg - ID:1 = PID file to read
pid_file = args[1]
script_name = args[2]
try:
f = open(pid_file)
data = f.readline()
pid = data.strip()
cmd = "ps -p %s --no-heading" % pid
res = is_pid_running(cmd)

if res:
return ERR_PID_SCRIPT_RUNNING
else:
# It isn't running, that is good.
return SUCCESS_EXIT_CODE

except Exception, e:
# Something happened with the file
print e
print "Checking process list for command"
res = is_script_running(script_name)
# If script is running and file not found
# exit, otherwise success
if res == True:
return ERR_PS_SCRIPT_RUNNING
else:
return SUCCESS_EXIT_CODE

return -1

if __name__ == '__main__':
res = main(sys.argv)
sys.exit(res)

4 comments:

Clément said...

Hi,
thank you for this script :)

I have a concern however: when running
ps aux | grep something
while the process "something" is not running on my computer returns (one line):
clement 5421 0.0 0.0 3600 764 pts/2 R+ 09:33 0:00 grep something

So the check_ps_cmd return a line which contains the name of the script I'm looking for even if it is not running.

The solution I found is to use the "pgrep" command instead of the ps aux/grep combination.

Hoping this comment can help,

Best regards,

Clément.

Berlin Brown said...

Good job. Thanks. People keeping telling me I need to use pgrep. I normally work with different systems, BSD, AIX, etc. I am kind of conservative on which commands to use and haven't used pgrep as much.

Also, the python example is a little verbose. In the future I hope to update it. Using python for launching processes is useful, my implementation is a little dated.

Priya angel said...
This comment has been removed by the author.
Priya angel said...

Enjoyed reading the article above, really explains everything in detail, the article is very interesting and effective. Thank you and good luck for the upcoming articles learn python training in Bangalore