diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index 23e895d6..ef9c2d5a 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -15,7 +15,7 @@ import sys import time import traceback -from gunicorn.pidfile import set_pidfile, unlink_pidfile +from gunicorn.pidfile import Pidfile from gunicorn.sock import create_socket from gunicorn.workers.sync import SyncWorker from gunicorn import util @@ -92,7 +92,8 @@ class Arbiter(object): self.pid = os.getpid() self.init_signals() self.LISTENER = create_socket(self.cfg) - self.pidfile = set_pidfile(self.pid, self.cfg.pidfile, self.pidfile) + self.pidfile = Pidfile(self.cfg.pidfile) + self.pidfile.create(self.pid) self.log.info("Arbiter booted") self.log.info("Listening at: %s" % self.LISTENER) @@ -152,14 +153,14 @@ class Arbiter(object): self.log.info("Unhandled exception in main loop:\n%s" % traceback.format_exc()) self.stop(False) - if self.pidfile: - unlink_pidfile(self.pid, self.pidfile) + if self.pidfile is not None: + self.pidfile.unlink() sys.exit(-1) self.stop() self.log.info("Shutting down: %s" % self.master_name) - if self.pidfile: - unlink_pidfile(self.pid, self.pidfile) + if self.pidfile is not None: + self.pidfile.unlink() sys.exit(0) def handle_chld(self, sig, frame): @@ -285,9 +286,8 @@ class Arbiter(object): """\ Relaunch the master and workers. """ - if self.pidfile: - old_pidfile = "%s.oldbin" % self.pidfile - self.pidfile = set_pidfile(self.pid, old_pidfile) + if self.pidfile is not None: + self.pidfile.rename("%s.oldbin" % self.pidfile.path) self.reexec_pid = os.fork() if self.reexec_pid != 0: diff --git a/gunicorn/pidfile.py b/gunicorn/pidfile.py index bdcac048..10756999 100644 --- a/gunicorn/pidfile.py +++ b/gunicorn/pidfile.py @@ -10,52 +10,60 @@ import os import tempfile -def set_pidfile(pid, path, oldpath=None): - oldpid = valid_pidfile(path) - if oldpid: - if oldpath is not None and path == oldpath and \ - oldpid == os.getpid(): - return path - raise RuntimeError("Already running on PID %s " \ - "(or pid file '%s' is stale)" % (os.getpid(), path)) - - if oldpath: - unlink_pidfile(pid, path) - - # write pidfile - fd, fname = tempfile.mkstemp(dir=os.path.dirname(path)) - os.write(fd, "%s\n" % pid) - os.rename(fname, path) - os.close(fd) - return path +class Pidfile(object): -def unlink_pidfile(pid, path): - """ delete pidfile""" - try: - with open(path, "r") as f: - pid1 = int(f.read() or 0) - - if pid1 == pid: - os.unlink(path) - except: - pass - -def valid_pidfile(path): - """ Validate pidfile and make it stale if needed""" - try: - with open(path, "r") as f: - wpid = int(f.read() or 0) + def __init__(self, path): + self.path = path + self.pid = None + + def create(self, pid): + oldpid = self.validate() + if oldpid: + if oldpid == os.getpid(): + return + raise RuntimeError("Already running on PID %s " \ + "(or pid file '%s' is stale)" % (os.getpid(), self.path)) - if wpid <= 0: return None - - try: - os.kill(wpid, 0) - return wpid - except OSError, e: - if e[0] == errno.ESRCH: - return - raise - except IOError, e: - if e[0] == errno.ENOENT: - return - raise \ No newline at end of file + self.pid = pid + + # write pidfile + fd, fname = tempfile.mkstemp(dir=os.path.dirname(self.path)) + os.write(fd, "%s\n" % self.pid) + os.rename(fname, self.path) + os.close(fd) + + def rename(self, path): + self.unlink() + self.path = path + self.create(self.pid) + + def unlink(self): + """ delete pidfile""" + try: + with open(self.path, "r") as f: + pid1 = int(f.read() or 0) + + if pid1 == self.pid: + os.unlink(self.path) + except: + pass + + def validate(self): + """ Validate pidfile and make it stale if needed""" + try: + with open(self.path, "r") as f: + wpid = int(f.read() or 0) + + if wpid <= 0: return None + + try: + os.kill(wpid, 0) + return wpid + except OSError, e: + if e[0] == errno.ESRCH: + return + raise + except IOError, e: + if e[0] == errno.ENOENT: + return + raise \ No newline at end of file