Python: módulo para crear un archivo de locking basado en PID?

Estoy escribiendo un script de Python que puede o no (dependiendo de un montón de cosas) ejecutarse durante mucho tiempo, y me gustaría asegurarme de que varias instancias (iniciadas a través de cron) no se paren entre sí. . La forma lógica de hacer esto parece ser un archivo de locking basado en PID … Pero no quiero reinventar la rueda si ya hay un código para hacer esto.

Entonces, ¿hay un módulo de Python que gestione los detalles de un archivo de locking basado en PID?

Si puede usar GPLv2, Mercurial tiene un módulo para eso:

http://bitbucket.org/mirror/mercurial/src/tip/mercurial/lock.py

Ejemplo de uso:

from mercurial import error, lock try: l = lock.lock("/path/to/lock", timeout=600) # wait at most 10 minutes # do something except error.LockHeld: # couldn't take the lock else: l.release() 

Esto podría ser de ayuda para usted: lockfile

Creo que encontrarás la información necesaria aquí . La página en cuestión se refiere a un paquete para crear demonios en Python: este proceso implica la creación de un archivo de locking PID.

He estado bastante descontento con todo eso, así que escribí esto:

 class Pidfile(): def __init__(self, path, log=sys.stdout.write, warn=sys.stderr.write): self.pidfile = path self.log = log self.warn = warn def __enter__(self): try: self.pidfd = os.open(self.pidfile, os.O_CREAT|os.O_WRONLY|os.O_EXCL) self.log('locked pidfile %s' % self.pidfile) except OSError as e: if e.errno == errno.EEXIST: pid = self._check() if pid: self.pidfd = None raise ProcessRunningException('process already running in %s as pid %s' % (self.pidfile, pid)); else: os.remove(self.pidfile) self.warn('removed staled lockfile %s' % (self.pidfile)) self.pidfd = os.open(self.pidfile, os.O_CREAT|os.O_WRONLY|os.O_EXCL) else: raise os.write(self.pidfd, str(os.getpid())) os.close(self.pidfd) return self def __exit__(self, t, e, tb): # return false to raise, true to pass if t is None: # normal condition, no exception self._remove() return True elif t is PidfileProcessRunningException: # do not remove the other process lockfile return False else: # other exception if self.pidfd: # this was our lockfile, removing self._remove() return False def _remove(self): self.log('removed pidfile %s' % self.pidfile) os.remove(self.pidfile) def _check(self): """check if a process is still running the process id is expected to be in pidfile, which should exist. if it is still running, returns the pid, if not, return False.""" with open(self.pidfile, 'r') as f: try: pidstr = f.read() pid = int(pidstr) except ValueError: # not an integer self.log("not an integer: %s" % pidstr) return False try: os.kill(pid, 0) except OSError: self.log("can't deliver signal to %s" % pid) return False else: return pid class ProcessRunningException(BaseException): pass 

para ser utilizado algo como esto:

 try: with Pidfile(args.pidfile): process(args) except ProcessRunningException: print "the pid file is in use, oops." 

Sé que este es un hilo antiguo, pero también creé un locking simple que solo se basa en bibliotecas nativas de python:

 import fcntl import errno class FileLock: def __init__(self, filename=None): self.filename = os.path.expanduser('~') + '/LOCK_FILE' if filename is None else filename self.lock_file = open(self.filename, 'w+') def unlock(self): fcntl.flock(self.lock_file, fcntl.LOCK_UN) def lock(self, maximum_wait=300): waited = 0 while True: try: fcntl.flock(self.lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB) return True except IOError as e: if e.errno != errno.EAGAIN: raise e else: time.sleep(1) waited += 1 if waited >= maximum_wait: return False 

Hay una receta en ActiveState para crear archivos de locking .

Para generar el nombre de archivo, puede usar os.getpid () para obtener el PID.