teoria - programacion pid python
Python: módulo para crear un archivo de bloqueo basado en PID? (6)
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 bloqueo 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 por ahí que administre los detalles de un archivo de bloqueo basado en PID?
Creo que encontrarás la información necesaria here . 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 bloqueo PID.
Esto podría ser de ayuda para usted: lockfile
Hay una receta en ActiveState para crear archivos de bloqueo .
Para generar el nombre de archivo puede usar os.getpid() para obtener el PID.
He estado bastante descontento con todos esos, 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 bloqueo simple que solo se basa en las 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
Si puedes 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()