[Zope-Checkins] CVS: ZODB3/zdaemon - Daemon.py:1.11.8.1 ZDaemonLogging.py:1.4.8.1 SignalPasser.py:NONE

Guido van Rossum guido@python.org
Thu, 17 Oct 2002 18:10:48 -0400


Update of /cvs-repository/ZODB3/zdaemon
In directory cvs.zope.org:/tmp/cvs-serv522

Modified Files:
      Tag: ZODB3-3_1-branch
	Daemon.py ZDaemonLogging.py 
Removed Files:
      Tag: ZODB3-3_1-branch
	SignalPasser.py 
Log Message:
Merge trunk; fixes and refactorings by ChrisM, presentation by Guido.


=== ZODB3/zdaemon/Daemon.py 1.11 => 1.11.8.1 ===
--- ZODB3/zdaemon/Daemon.py:1.11	Wed Aug 14 18:12:52 2002
+++ ZODB3/zdaemon/Daemon.py	Thu Oct 17 18:10:48 2002
@@ -15,13 +15,31 @@
 import os, sys, time, signal
 from ZDaemonLogging import pstamp
 import zLOG
-from SignalPasser import SignalPasser
+
+# If zdaemon finds that it is continuously respawning more than 10
+# times in 2 minutes, it will assume that there is an error, log a
+# PANIC level message, and exit.
+RESPAWN_TIME = 120 # 2 minutes
+RESPAWN_LIMIT = 10 # 10 times
 
 pyth = sys.executable
 
 class DieNow(Exception):
     pass
 
+class SignalPasser:
+    """ A class used for passing signal that the daemon receives along to
+    its child """
+    def __init__(self, pid):
+        self.pid = pid
+
+    def __call__(self, signum, frame):
+        # send the signal to our child
+        os.kill(self.pid, signum)
+        # we want to die ourselves if we're signaled with SIGTERM or SIGINT
+        if signum in [signal.SIGTERM, signal.SIGINT]:
+            raise DieNow
+
 def run(argv, pidfile=''):
     if os.environ.has_key('ZDAEMON_MANAGED'):
         # We're being run by the child.
@@ -32,7 +50,17 @@
     if not os.environ.has_key('Z_DEBUG_MODE'):
         detach() # detach from the controlling terminal
 
+    starttimes = [] # for RESPAWN_LIMIT
     while 1:
+        # Give up if respawning too often
+        starttimes.append(time.time())
+        if len(starttimes) > RESPAWN_LIMIT:
+            del starttimes[0]
+            if starttimes[-1] - starttimes[0] < RESPAWN_TIME:
+                pstamp('Respawning more than %d times in %d seconds. Quit.' %
+                       (RESPAWN_LIMIT, RESPAWN_TIME), zLOG.PANIC)
+                sys.exit(1)
+            del starttimes[0]
         try:
             pid = os.fork()
             if pid:
@@ -42,8 +70,8 @@
                 interesting = [1, 2, 3, 10, 12, 15]
                 # ie. HUP, INT, QUIT, USR1, USR2, TERM
                 for sig in interesting:
-                    signal.signal(sig, SignalPasser(sig))
-                pstamp('Houston, we have forked: pid %s' % pid, zLOG.INFO)
+                    signal.signal(sig, SignalPasser(pid))
+                pstamp('Started subprocess: pid %s' % pid, zLOG.INFO)
                 write_pidfile(pidfile)
                 p,s = wait(pid) # waitpid will block until child exit
                 if s:
@@ -79,7 +107,7 @@
 def write_pidfile(pidfile):
     if pidfile:
         pf = open(pidfile, 'w+')
-        pf.write(("%s" % os.getpid()))
+        pf.write(("%s\n" % os.getpid()))
         pf.close()
 
 def wait(pid):
@@ -101,28 +129,19 @@
     elif os.WIFSIGNALED(s):
         signum = os.WTERMSIG(s)
         signame = get_signal_name(signum)
-        msg = "terminated by signal %s(%s)" % (signame,
-                                              signum)
-        # We'd like to report whether a core file
-        # was produced, but there isn't a standard
-        # way to check.  It seems that some
-        # (many?) Unixes use bit 0x80 in the wait
-        # status, but how to tell?  A simple
-        # alternative is to assume that no core
-        # file was produced if the wait status is
-        # exactly equal to the signal.  Otherwise,
-        # there might be a core file and it's
-        # useful to print the wait status.
-        if signum != s:
-            msg += ", wait status: %s" % signum
+        msg = "terminated by signal %s(%s)" % (signame, signum)
+        if hasattr(os, 'WCOREDUMP'):
+            iscore = os.WCOREDUMP(s)
+        else:
+            iscore = s & 0x80
+        if iscore:
+            msg += " (core dumped)"
     else:
         # XXX what should we do here?
         signum = os.WSTOPSIG(s)
         signame = get_signal_name(signum)
-        msg = "stopped by signal %s(%s)" % (signame,
-                                            signum)
-    pstamp('Aiieee! Process %s %s' % (p, msg),
-           zLOG.ERROR)
+        msg = "stopped by signal %s(%s)" % (signame, signum)
+    pstamp('Process %s %s' % (p, msg), zLOG.ERROR)
 
 _signals = None
 


=== ZODB3/zdaemon/ZDaemonLogging.py 1.4 => 1.4.8.1 ===
--- ZODB3/zdaemon/ZDaemonLogging.py:1.4	Wed Aug 14 18:12:52 2002
+++ ZODB3/zdaemon/ZDaemonLogging.py	Thu Oct 17 18:10:48 2002
@@ -17,5 +17,4 @@
 from zLOG import LOG
 
 def pstamp(message, sev):
-    LOG("zdaemon", sev,
-        ("zdaemon: %s: %s" % (ctime(time()), message)))
+    LOG("zdaemon", sev, message)

=== Removed File ZODB3/zdaemon/SignalPasser.py ===