[Zope-Checkins] CVS: ZODB3/zdaemon - zdaemon.py:1.13

Guido van Rossum guido@python.org
Tue, 12 Nov 2002 14:53:58 -0500


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

Modified Files:
	zdaemon.py 
Log Message:
At considerable complexity, added the last desired feature: when
stopping the process, send a SIGTERM and a while later send a SIGKILL.

Now it's time to refactor and add unit tests and doc strings.


=== ZODB3/zdaemon/zdaemon.py 1.12 => 1.13 ===
--- ZODB3/zdaemon/zdaemon.py:1.12	Tue Nov 12 12:34:08 2002
+++ ZODB3/zdaemon/zdaemon.py	Tue Nov 12 14:53:58 2002
@@ -57,16 +57,12 @@
 """
 XXX TO DO
 
-- The "stop" command should first send a SIGTERM, then sleep
-  backofflimit seconds, then send SIGKILL, and keep repeating SIGKILL
-  until it actually dies.
-
 - True OO design -- use multiple classes rather than folding
   everything into one class.
 
 - Add unit tests.
 
-- Add docstrings.
+- Add doc strings.
 
 """
 
@@ -311,8 +307,9 @@
         os.setsid()
 
     mood = 1 # 1: up, 0: down, -1: suicidal
-    delay = 0 # If nonzero, delay starting until this time
+    delay = 0 # If nonzero, delay starting or killing until this time
     appid = 0 # Application pid; indicates status (0 == not running)
+    killing = 0 # If true, send SIGKILL when delay expires
 
     def runforever(self):
         self.info("daemon manager started")
@@ -329,6 +326,9 @@
                 timeout = max(0, min(timeout, self.delay - time.time()))
                 if timeout <= 0:
                     self.delay = 0
+                    if self.killing and self.appid:
+                        self.killapp(signal.SIGKILL)
+                        self.delay = time.time() + self.backofflimit
             try:
                 r, w, x = select.select(r, w, x, timeout)
             except select.error, err:
@@ -397,6 +397,7 @@
         self.mood = 1 # Up
         self.backoff = 0
         self.delay = 0
+        self.killing = 0
         if not self.appid:
             self.forkandexec()
             self.sendreply("Application started")
@@ -407,9 +408,12 @@
         self.mood = 0 # Down
         self.backoff = 0
         self.delay = 0
+        self.killing = 0
         if self.appid:
-            os.kill(self.appid, signal.SIGTERM)
+            self.killapp(signal.SIGTERM)
             self.sendreply("Sent SIGTERM")
+            self.killing = 1
+            self.delay = time.time() + self.backofflimit
         else:
             self.sendreply("Application already stopped")
 
@@ -417,9 +421,12 @@
         self.mood = 1 # Up
         self.backoff = 0
         self.delay = 0
+        self.killing = 0
         if self.appid:
-            os.kill(self.appid, signal.SIGTERM)
+            self.killapp(signal.SIGTERM)
             self.sendreply("Sent SIGTERM; will restart later")
+            self.killing = 1
+            self.delay = time.time() + self.backofflimit
         else:
             self.forkandexec()
             self.sendreply("Application started")
@@ -428,9 +435,12 @@
         self.mood = -1 # Suicidal
         self.backoff = 0
         self.delay = 0
+        self.killing = 0
         if self.appid:
-            os.kill(self.appid, signal.SIGTERM)
+            self.killapp(signal.SIGTERM)
             self.sendreply("Sent SIGTERM; will exit later")
+            self.killing = 1
+            self.delay = time.time() + self.backofflimit
         else:
             self.sendreply("Exiting now")
             self.info("Exiting")
@@ -448,9 +458,8 @@
         if not self.appid:
             self.sendreply("Application not running")
         else:
-            try:
-                os.kill(self.appid, sig)
-            except os.error, msg:
+            msg = self.killapp(sig)
+            if msg:
                 self.sendreply("Kill %d failed: %s" % (sig, msg))
             else:
                 self.sendreply("Signal %d sent" % sig)
@@ -500,6 +509,17 @@
         except socket.error, msg:
             self.problem("Error sending reply: %s" % str(msg))
 
+    def killapp(self, sig):
+        if self.appid:
+            try:
+                os.kill(self.appid, sig)
+            except os.error, msg:
+                self.problem("Couldn't send signal %d to pid %d: %s" %
+                             (sig, self.appid, msg))
+                return msg
+            self.info("Sent signal %d to pid %d" % (sig, self.appid))
+        return None
+
     backoff = 0
     lasttime = None
 
@@ -554,6 +574,8 @@
         self.waitstatus = None
         if pid == self.appid:
             self.appid = 0
+            self.killing = 0
+            self.delay = 0
             self.governor()
         if os.WIFEXITED(sts):
             es = os.WEXITSTATUS(sts)