Zuvor habe ich eine Version nur mit der Sperrdatei geschrieben, diese war jedoch unbeliebt (?). Daher habe ich eine Version mit der PID-Datei erstellt. Es ist einfach zu bedienen, da es als Dekorateur definiert ist. Gehen Sie einfach wie folgt vor:
@singleprocess
def main();
pass
Die Operation ist wie folgt.
Die PID-Datei wird unter / tmp abgelegt, und die Sicherheit wird nicht berücksichtigt. Um es in der Produktion verwenden zu können, müssen der getSignature-Algorithmus und der Speicherort der PID-Datei je nach Anwendung möglicherweise geändert werden.
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