[Zope-Checkins] CVS: Zope/lib/python/nt_svcutils - service.py:1.4.2.1

Jeremy Hylton jeremy at zope.com
Mon Jan 26 12:13:56 EST 2004


Update of /cvs-repository/Zope/lib/python/nt_svcutils
In directory cvs.zope.org:/tmp/cvs-serv20862/Zope/lib/python/nt_svcutils

Modified Files:
      Tag: jeremy-windows-service-branch
	service.py 
Log Message:
Checkpoint of code to redirect stdout/stderr of spwaned
process to a file.


=== Zope/lib/python/nt_svcutils/service.py 1.4 => 1.4.2.1 ===
--- Zope/lib/python/nt_svcutils/service.py:1.4	Tue Jan 13 17:37:02 2004
+++ Zope/lib/python/nt_svcutils/service.py	Mon Jan 26 12:13:55 2004
@@ -14,6 +14,7 @@
 
 """Windows Services installer/controller for Zope/ZEO/ZRS instance homes"""
 
+import msvcrt
 import win32api
 import win32con
 import win32event
@@ -77,6 +78,7 @@
         win32event.SetEvent(self.hWaitStop)
 
     def createProcess(self, cmd):
+        self.start_time = time.time()
         if self.capture_io:
             return self.createProcessCaptureIO(cmd)
         else:
@@ -126,56 +128,93 @@
         # BACKOFF_CLEAR_TIME seconds, the backoff stats are reset.
 
         # the initial number of seconds between process start attempts
-        backoff_interval = BACKOFF_INITIAL_INTERVAL
+        self.backoff_interval = BACKOFF_INITIAL_INTERVAL
         # the cumulative backoff seconds counter
-        backoff_cumulative = 0
+        self.backoff_cumulative = 0
 
         import servicemanager
         self.logmsg(servicemanager.PYS_SERVICE_STARTED)
         
         while 1:
-            start_time = time.time()
             info, handles = self.createProcess(self.start_cmd)
             # XXX integrate handles into the wait and make a loop
             # that reads data and writes it into a logfile
             self.hZope = info[0] # the pid
-            if backoff_interval > BACKOFF_INITIAL_INTERVAL:
+            # XXX why the test before the log message?
+            if self.backoff_interval > BACKOFF_INITIAL_INTERVAL:
                 self.info("created process")
+            if not (self.run(handles) and self.checkRestart()):
+                break
+        self.logmsg(servicemanager.PYS_SERVICE_STOPPED)
+
+    def run(self, handles):
+        """Monitor the daemon process.
+
+        Returns True if the service should continue running and
+        False if the service process should exit.  On True return,
+        the process exited unexpectedly and the caller should restart
+        it.
+        """
+
+        keep_running = True
+        # ignore stdin
+        print handles
+        win32file.CloseHandle(handles[0])
+        fd = msvcrt.open_osfhandle(handles[1], 0)
+        stdout = os.fdopen(fd)
+        fd = msvcrt.open_osfhandle(handles[2], 0)
+        stderr = os.fdopen(fd)
+##        stdout = os.fdopen(msvcrt.open_osfhandle(handles[1], 0))
+##        stderr = os.fdopen(msvcrt.open_osfhandle(handles[2], 0))
+
+        while 1:
             rc = win32event.WaitForMultipleObjects(
-                (self.hWaitStop, self.hZope) + handles, 0, win32event.INFINITE)
+                (self.hWaitStop, self.hZope) + handles[1:], 0, win32event.INFINITE)
             if rc == win32event.WAIT_OBJECT_0:
                 # user sent a stop service request
                 self.SvcStop()
+                keep_running = False
                 break
-            else:
+            elif rc == win32event.WAIT_OBJECT_0 + 1:
                 # user did not send a service stop request, but
                 # the process died; this may be an error condition
                 status = win32process.GetExitCodeProcess(self.hZope)
-                if status == 0:
-                    # the user shut the process down from the web
-                    # interface (or it otherwise exited cleanly)
-                    break
-                else:
-                    # this was an abormal shutdown.
-                    if backoff_cumulative > BACKOFF_MAX:
-                        self.error("restarting too frequently; quit")
-                        self.SvcStop()
-                        break
-                    self.warning("sleep %s to avoid rapid restarts"
-                                 % backoff_interval)
-                    if time.time() - start_time > BACKOFF_CLEAR_TIME:
-                        backoff_interval = BACKOFF_INITIAL_INTERVAL
-                        backoff_cumulative = 0
-                    # XXX Since this is async code, it would be better
-                    # done by sending and catching a timed event (a
-                    # service stop request will need to wait for us to
-                    # stop sleeping), but this works well enough for me.
-                    time.sleep(backoff_interval)
-                    backoff_cumulative += backoff_interval
-                    backoff_interval *= 2
-
-        self.logmsg(servicemanager.PYS_SERVICE_STOPPED)
-
+                # exit status 0 means the user caused a clean shutdown,
+                # presumably via the web interface
+                keep_running = status != 0
+                break
+            else:
+                i = rc - (win32event.WAIT_OBJECT_0 + 2)
+                if i == 0:
+                    data = stdout.read(8192)
+                    self.info("stdout: %s" % data)
+                elif i == 1:
+                    data = stderr.read(8192)
+                    self.info("stderr: %s" % data)
+        stdout.close()
+        stderr.close()
+        return keep_running
+
+    def checkRestart(self):
+        # this was an abormal shutdown.
+        if self.backoff_cumulative > BACKOFF_MAX:
+            self.error("restarting too frequently; quit")
+            self.SvcStop()
+            return False
+        self.warning("sleep %s to avoid rapid restarts"
+                     % self.backoff_interval)
+        if time.time() - self.start_time > BACKOFF_CLEAR_TIME:
+            self.backoff_interval = BACKOFF_INITIAL_INTERVAL
+            self.backoff_cumulative = 0
+        # XXX Since this is async code, it would be better
+        # done by sending and catching a timed event (a
+        # service stop request will need to wait for us to
+        # stop sleeping), but this works well enough for me.
+        time.sleep(self.backoff_interval)
+        self.backoff_cumulative += self.backoff_interval
+        self.backoff_interval *= 2
+        return True
+        
     def createProcessCaptureIO(self, cmd):
         stdin = self.newPipe()
         stdout = self.newPipe()
@@ -198,6 +237,7 @@
         # circumstances of a service process.
         info = win32process.CreateProcess(None, cmd, None, None, True, 0,
                                           None, None, si)
+        print "createprocess", info
 
         win32file.CloseHandle(stdin[0])
         win32file.CloseHandle(stdout[1])




More information about the Zope-Checkins mailing list