[Zope-Checkins] CVS: Zope/ZServer - FTPServer.py:1.23.10.1 HTTPServer.py:1.41.6.1.2.1 ICPServer.py:1.2.10.1

Toby Dickenson tdickenson@geminidataloggers.com
Thu, 10 Oct 2002 13:28:24 -0400


Update of /cvs-repository/Zope/ZServer
In directory cvs.zope.org:/tmp/cvs-serv27621/ZServer

Modified Files:
      Tag: toby-clean-shutdown-branch
	FTPServer.py HTTPServer.py ICPServer.py 
Log Message:
draft implementation of the clean shutdown proposal. ZMI and signal-based shutdown methods now set a global variable. This global variable causes the main medusa loop to return. We then gradually shut down sockets, in the right order. If any clients are slowly downloading a file then they can cause the shutdown to be delayed by up to 30 seconds, to allow them time to complete. This is true unless the shutdown was triggered by SIGTERM - we need to shutdown fast because the whole machine might be going down, and we can expect a SIGKILL within a few seconds.

=== Zope/ZServer/FTPServer.py 1.23 => 1.23.10.1 ===
--- Zope/ZServer/FTPServer.py:1.23	Wed Aug 14 17:16:50 2002
+++ Zope/ZServer/FTPServer.py	Thu Oct 10 13:27:53 2002
@@ -609,6 +609,11 @@
                         self.port
                         ))
 
+    def clean_shutdown_control(self,phase,time_in_this_phase):
+        if phase==2:
+            self.log_info('closing FTP to new connections')
+            self.close()
+
     def log_info(self, message, type='info'):
         if self.shutup: return
         asyncore.dispatcher.log_info(self, message, type)


=== Zope/ZServer/HTTPServer.py 1.41.6.1 => 1.41.6.1.2.1 ===
--- Zope/ZServer/HTTPServer.py:1.41.6.1	Thu Oct  3 22:29:49 2002
+++ Zope/ZServer/HTTPServer.py	Thu Oct 10 13:27:53 2002
@@ -281,7 +281,8 @@
 class zhttp_channel(http_channel):
     "http channel"
 
-    closed=0
+    closed = 0
+    no_more_requests = 0
     zombie_timeout=100*60 # 100 minutes
     max_header_len = 8196
 
@@ -302,10 +303,23 @@
 
     push_with_producer=push
 
+    def clean_shutdown_control(self,phase,time_in_this_phase):
+        if phase==3:
+            # This is the shutdown phase where we are trying to finish processing
+            # outstanding requests, and not accept any more
+            self.no_more_requests = 1
+            if self.working or self.writable():
+                # We are busy working on an old request. Try to stall shutdown
+                return 1
+            else:
+                # We are no longer busy. Close ourself and allow shutdown to proceed
+                self.close()
+                return 0
+
     def work(self):
         "try to handle a request"
         if not self.working:
-            if self.queue:
+            if self.queue and not self.no_more_requests:
                 self.working=1
                 try: module_name, request, response=self.queue.pop(0)
                 except: return
@@ -367,6 +381,11 @@
                         self.server_name,
                         self.server_port
                         ))
+
+    def clean_shutdown_control(self,phase,time_in_this_phase):
+        if phase==2:
+            self.log_info('closing HTTP to new connections')
+            self.close()
 
     def log_info(self, message, type='info'):
         if self.shutup: return


=== Zope/ZServer/ICPServer.py 1.2 => 1.2.10.1 ===
--- Zope/ZServer/ICPServer.py:1.2	Wed Aug 14 17:16:50 2002
+++ Zope/ZServer/ICPServer.py	Thu Oct 10 13:27:53 2002
@@ -33,6 +33,7 @@
 class BaseICPServer(asyncore.dispatcher):
 
     REQUESTS_PER_LOOP = 4
+    _shutdown = 0
 
     def __init__ (self,ip,port):
         asyncore.dispatcher.__init__(self)
@@ -45,6 +46,21 @@
             addr = ip
         self.log_info('ICP server started\n\tAddress: %s\n\tPort: %s' % (addr,port) )
 
+    def clean_shutdown_control(self,phase,time_in_this_phase):
+        if phase==1:
+            # Stop responding to requests.
+            if not self._shutdown:
+                self._shutdown = 1
+                self.log_info('shutting down ICP')
+            if time_in_this_phase<2.0:
+                # We have not yet been deaf long enough for our front end proxies to notice.
+                # Do not allow shutdown to proceed yet
+                return 1
+            else:
+                # Shutdown can proceed. We dont need a socket any more
+                self.close()
+                return 0
+
     def handle_read(self):
         for i in range(self.REQUESTS_PER_LOOP):
             try:
@@ -61,7 +77,7 @@
                         self.socket.sendto(reply,whence)
 
     def readable(self):
-        return 1
+        return not self._shutdown
 
     def writable(self):
         return 0