diff options
author | David Stanek <dstanek@dstanek.com> | 2009-07-16 00:27:09 -0400 |
---|---|---|
committer | David Stanek <dstanek@dstanek.com> | 2009-07-16 00:27:09 -0400 |
commit | d9bee58819dddb3ce47f1ee7df555ef20617d1cd (patch) | |
tree | 1eb5711aa1d1978a469fd2207470a0d595073d9c | |
parent | 36bd8bfa631b302aa3ae2d73aafadd260ecb55e9 (diff) | |
download | flup-d9bee58819dddb3ce47f1ee7df555ef20617d1cd.tar.gz |
Adding initial support for purging child processes in a safe way using SIGUSR1.
-rw-r--r-- | flup/server/preforkserver.py | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/flup/server/preforkserver.py b/flup/server/preforkserver.py index 5eded2c..beb856e 100644 --- a/flup/server/preforkserver.py +++ b/flup/server/preforkserver.py @@ -99,6 +99,9 @@ class PreforkServer(object): # free to process requests. self._children = {} + self._children_to_purge = [] + self._last_purge = 0 + def run(self, sock): """ The main loop. Pass a socket that is ready to accept() client @@ -126,15 +129,17 @@ class PreforkServer(object): r = [x['file'] for x in self._children.values() if x['file'] is not None] - if len(r) == len(self._children): + if len(r) == len(self._children) and not self._children_to_purge: timeout = None else: # There are dead children that need to be reaped, ensure - # that they are by timing out, if necessary. + # that they are by timing out, if necessary. Or there are some + # children that need to die. timeout = 2 + w = (time.time() > self._last_purge + 10) and self._children_to_purge or [] try: - r, w, e = select.select(r, [], [], timeout) + r, w, e = select.select(r, w, [], timeout) except select.error, e: if e[0] != errno.EINTR: raise @@ -163,6 +168,20 @@ class PreforkServer(object): d['file'] = None d['avail'] = False + for child in w: + # purging child + child.send('bye, bye') + del self._children_to_purge[self._children_to_purge.index(child)] + self._last_purge = time.time() + + # Try to match it with a child. (Do we need a reverse map?) + for pid,d in self._children.items(): + if child is d['file']: + d['file'].close() + d['file'] = None + d['avail'] = False + break + # Reap children. self._reapChildren() @@ -396,8 +415,12 @@ class PreforkServer(object): # Do nothing (breaks us out of select and allows us to reap children). pass + def _usr1Handler(self, signum, frame): + self._children_to_purge = [x['file'] for x in self._children.values() + if x['file'] is not None] + def _installSignalHandlers(self): - supportedSignals = [signal.SIGINT, signal.SIGTERM] + supportedSignals = [signal.SIGINT, signal.SIGTERM, signal.SIGUSR1] if hasattr(signal, 'SIGHUP'): supportedSignals.append(signal.SIGHUP) @@ -406,6 +429,8 @@ class PreforkServer(object): for sig in supportedSignals: if hasattr(signal, 'SIGHUP') and sig == signal.SIGHUP: signal.signal(sig, self._hupHandler) + elif sig == signal.SIGUSR1: + signal.signal(sig, self._usr1Handler) else: signal.signal(sig, self._intHandler) |