Frage

Ich bin ein Python-Skript zu schreiben, die nicht (auf einer Reihe von Dingen abhängig) laufen für eine lange Zeit kann oder nicht, und ich möchte sicherstellen, dass mehrere Instanzen (via cron gestartet wird) nicht Schritt auf jeweils anderen Zehen. Der logische Weg, dies zu tun scheint eine PID-basierte lockfile zu sein ... Aber ich will nicht das Rad neu erfinden, wenn bereits Code ist, dies zu tun.

So

gibt es ein Python-Modul gibt, die die Details eines PID-basierten lockfile verwalten?

War es hilfreich?

Lösung

Wenn Sie GPLv2 verwenden können, Mercurial hat ein Modul für das:

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

Beispiel Nutzung:

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()

Andere Tipps

Dies könnte sein, dass Sie Hilfe: lockfile

Ich glaube, dass Sie die notwendigen Informationen finden hier . Die betreffende Seite bezieht sich auf ein Paket für Daemons in Python bauen. Dieser Prozess beinhaltet eine PID lockfile Erstellen

Ich habe ziemlich unglücklich mit all denen, so schrieb ich diese:

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

so etwas wie diese verwendet werden:

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

Ich weiß, das ist ein alter Thread, aber ich schuf auch eine einfache Sperre, die nativen Bibliotheken auf Python verlässt sich nur:

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

Es gibt ein Rezept auf Active auf der Schaffung von Lock-Dateien .

, um den Dateinamen generieren Sie verwenden können, os.getpid () die PID erhalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top