Check if Python Script is already running

Martin picture Martin · Apr 22, 2016 · Viewed 20.9k times · Source

i would like my Python script to check, if it is already running and if yes, kill the old process. i tried this, but it doesn't really work...

import os
import subprocess
import signal

process_name = "python " + os.path.abspath(__file__)
proc = subprocess.Popen(["pgrep", process_name], stdout=subprocess.PIPE)

# Kill process.
for pid in proc.stdout:
    os.kill(int(pid), signal.SIGTERM)
    # Check if the process that we killed is alive.
    try:
        os.kill(int(pid), 0)
        raise Exception("""wasn't able to kill the process
                          HINT:use signal.SIGKILL or signal.SIGABORT""")
    except OSError as ex:
        continue

It doesn't kill the old process and runs multiple times now.

Answer

Dan Cornilescu picture Dan Cornilescu · Apr 22, 2016

Determining if a python script is running using your pgrep based method is not reliable. For example:

> ps -ef | grep 'python sleep.py'
userid  21107  2069  0 12:51 pts/3    00:00:00 python sleep.py
userid  21292  2069  0 13:08 pts/3    00:00:00 grep python sleep.py
> pgrep 'python sleep.py'
> 

Additional difficulties in identifying a running python script by its name:

  • the actual python string may differ, depending on how the script is executed, for example it may look like this:

/usr/bin/python2.7 sleep.py

  • using the os.path.abspath(__file__) method to locate the script in the process name may fail if the script is a symlink to the actual file and can be executed from both locations

Example:

> cat abs_path.py
import os
print os.path.abspath(__file__)
> ls -l abs_path.py 
lrwxrwxrwx 1 userid at 15 Apr 22 13:22 abs_path.py -> bin/abs_path.py
> python abs_path.py
/home/userid/abs_path.py
> python bin/abs_path.py
/home/userid/bin/abs_path.py
  • processes (including those from python scripts) can actually change their name during execution (maybe not in your script's case, true)

My personal preference in approaching such problem is to have the script create a pidfile in a unique, well known location in which it'll place its own pid. This makes determining the pid of a potentially already running process much more reliable.

You'll still have to take into account the race condition in creating the pidfile and reliably writing into it self's pid. Typically re-checking the file content and committing suicide if mismatches are detected is sufficient to ensure at most a single running process instance exists, regardless of how the process is actually named.