Auparavant, j'écrivais une version en utilisant uniquement le fichier de verrouillage, mais c'était impopulaire (?), J'ai donc créé une version en utilisant le fichier pid. Il est facile à utiliser car il est défini comme un décorateur. Faites ce qui suit:
@singleprocess
def main();
pass
L'opération est la suivante.
Le fichier pid est spécifié pour être placé sous / tmp, et la sécurité n'est pas prise en compte. Pour l'utiliser en production, il peut être nécessaire de modifier l'algorithme getSignature et l'emplacement du fichier pid en fonction de l'application.
def singleprocess(func):
def basenameWithoutExt(path):
return os.path.splitext(os.path.basename(path))[0]
def getSignature(pid):
processDirectory = '/proc/%d/' % (pid,)
if os.path.isdir(processDirectory):
args = open(processDirectory + 'cmdline').read().split("\x00")
return [os.path.basename(args[0]), os.path.basename(args[1])]
return None
@contextmanager
def filelockingcontext(path):
open(path, "a").close() #ensure file to exist for locking
with open(path) as lockFd:
fcntl.flock(lockFd, fcntl.LOCK_EX)
yield
fcntl.flock(lockFd, fcntl.LOCK_UN)
def wrapper(*args, **kwargs):
pidFilePath = tempfile.gettempdir() + '/' + basenameWithoutExt(sys.argv[0]) + '.pid'
with filelockingcontext(pidFilePath):
runningPid = ""
with open(pidFilePath) as readFd:
runningPid = readFd.read()
if runningPid != "" and getSignature(int(runningPid)) == getSignature(os.getpid()) is not None:
print("process already exists", file=sys.stderr)
exit()
with open(pidFilePath, "w") as writeFd:
writeFd.write(str(os.getpid()))
try:
func(*args, **kwargs)
finally:
with filelockingcontext(pidFilePath):
os.remove(pidFilePath)
return wrapper
Recommended Posts