Monday, February 4, 2013

Allow only one instance of python script.

What if you need to run python script only if it's not already running? Or kill old copy before run new one? One of the way is:

  • Check if special file exists. If it's true, one copy of script is already running. Now kill it or exit from second copy.
  • Create temporary file with PID of script process.
  • Delete pid-file at the end of the script.
Here is the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import tempfile
import ctypes
import os

# Path to file storing PID of running script process. 
# Place it outside of methods in the beggining, or make sure it visible for all methods, which use it.
pid_file = tempfile.gettempdir() + 'tmp_armor_pid.txt'   

# This method checks if file pid_file exists. 
#  If it was found, depends of mode - exit, or kill process which PID is stored in file.  
def scriptStarter(mode = 'force'):
    '''
        if mode  = force - kill runing script and run new one
        if mode != force - run script only if it's not already running
    '''
    if os.path.exists(pid_file):
        print 'old copy found'
        if mode == 'force':
            print 'running copy found, killing it'
            # reading PID from file and convert it to int
            pid = int((open(pid_file).read()))  
            print 'pid have been read:', pid
            # If you use pythton 2.7 or above just use os.kill to terminate PID process.
            # In case of python 2.6 run method killing selected PID
            kill(pid)         

        else:
            print 'running copy found, leaving'
            # not force mode. Just don't run new copy. Leaving.
            raise SystemExit           

 # If we are here, mode == force, old copy killed, writing PID for new script process 
    open(pid_file, 'w').write(str(os.getpid()))  


def kill(pid):
    """kill function for Win32"""
    kernel32 = ctypes.windll.kernel32
    handle = kernel32.OpenProcess(1, 0, pid)
    return (0 != kernel32.TerminateProcess(handle, 0))

# Delete pid-file befor script finish.  
# Dont forget to run this method at the end of the script
# If you use PyQt call it in overloaded closeEvent() 
def removePIDfile():
    print 'deleting pidfile'
    try:
        os.remove(pid_file)
    except OSError:
        pass
    return


def main():
 # check if script is already running 
    scriptStarter('force')    
 '''YOUR SCRIPT CODE HERE'''
 
 # remove pid-file before exit.
 removePIDfile()

if __name__=="__main__":
    main()

1 comment: