Author: chrisz
Date: Thu Sep 29 15:05:09 2005
New Revision: 3357
Modified:
Webware/trunk/WebKit/AppServer.py
Webware/trunk/WebKit/AutoReloadingAppServer.py
Webware/trunk/WebKit/ThreadedAppServer.py
Log:
Cleaner shutdown sequence.
Modified: Webware/trunk/WebKit/AppServer.py
==============================================================================
--- Webware/trunk/WebKit/AppServer.py (original)
+++ Webware/trunk/WebKit/AppServer.py Thu Sep 29 15:05:09 2005
@@ -13,6 +13,11 @@
from threading import Thread, Event
+try: # backward compatibility for Python < 2.3
+ True, False
+except NameError:
+ True, False = 1, 0
+
"""
There is only one instance of AppServer, `globalAppServer` contains
that instance. Use it like::
@@ -93,7 +98,7 @@
self._app = self.createApplication()
self.loadPlugIns()
- self.running = 1
+ self.running = True
# @@ 2003-03 ib: shouldn't this just be in a subclass's __init__?
if self.isPersistent():
@@ -162,14 +167,14 @@
"""Shut down the AppServer.
Subclasses may override and normally follow this sequence:
- 1. set self._shuttingDown to 1
+ 1. set self._shuttingDown to True
2. class specific statements for shutting down
3. Invoke super's shutDown() e.g., ``AppServer.shutDown(self)``
"""
print "Shutting down the AppServer"
- self._shuttingDown = 1
- self.running = 0
+ self._shuttingDown = True
+ self.running = False
self._app.shutDown()
del self._plugIns
del self._app
Modified: Webware/trunk/WebKit/AutoReloadingAppServer.py
==============================================================================
--- Webware/trunk/WebKit/AutoReloadingAppServer.py (original)
+++ Webware/trunk/WebKit/AutoReloadingAppServer.py Thu Sep 29 15:05:09 2005
@@ -1,9 +1,3 @@
-from AppServer import AppServer
-import os
-from threading import Thread
-import time
-import sys
-import select
"""
This module defines `AutoReloadingAppServer`, a replacement for `AppServer`
@@ -18,14 +12,26 @@
.. inline:: AutoReloadingAppServer
"""
+from AppServer import AppServer
+import os
+from threading import Thread
+import time
+import sys
+import select
+
+try: # backward compatibility for Python < 2.3
+ True, False
+except NameError:
+ True, False = 1, 0
+
# Attempt to use python-fam (fam = File Alteration Monitor) instead of polling
# to see if files have changed. If python-fam is not installed, we fall back
# to polling.
try:
import _fam
- haveFam = 1
+ haveFam = True
except:
- haveFam = 0
+ haveFam = False
import ImportSpy
standardLibraryPrefix = '%s/lib/python%i.%i' % \
@@ -33,8 +39,8 @@
DefaultConfig = {
- 'AutoReload': 0,
- 'AutoReloadPollInterval': 1, # in seconds
+ 'AutoReload': False,
+ 'AutoReloadPollInterval': 1, # in seconds
}
@@ -59,8 +65,8 @@
def __init__(self,path=None):
"""Activate AutoReloading."""
AppServer.__init__(self,path)
- self._autoReload = 0
- self._shouldRestart = 0
+ self._autoReload = False
+ self._shouldRestart = False
self._requests = []
self._pipe = None
@@ -82,7 +88,7 @@
"""
print 'Stopping AutoReload Monitor'
sys.stdout.flush()
- self._shuttingDown = 1
+ self._shuttingDown = True
self.deactivateAutoReload()
AppServer.shutDown(self)
@@ -102,7 +108,7 @@
self.setting('AutoReloadPollInterval'), 'seconds'
self._fileMonitorThread = t = Thread(
target=self.fileMonitorThreadLoop)
- self._autoReload = 1
+ self._autoReload = True
t.setName('AutoReloadMonitor')
t.start()
@@ -112,7 +118,7 @@
This should be considered as a request, not a demand.
"""
- self._autoReload = 0
+ self._autoReload = False
if haveFam:
# Send a message down the pipe to wake up the monitor thread
# and tell him to quit.
@@ -180,7 +186,7 @@
def shouldRestart(self):
"""Tell the main thread to restart the server."""
- self._shouldRestart = 1
+ self._shouldRestart = True
def fileMonitorThreadLoop(self):
"""This the the main loop for the monitoring thread.
@@ -197,7 +203,7 @@
for f, mtime in ImportSpy.modloader.fileList().items():
if self.fileUpdated(f, mtime):
print '*** The file', f, 'has changed. The server is restarting now.'
- self._autoReload = 0
+ self._autoReload = False
return self.shouldRestart()
print 'Autoreload Monitor stopped'
sys.stdout.flush()
@@ -237,7 +243,7 @@
if self.fileUpdated(f, mtime):
print '*** The file', f, 'has changed.', \
'The server is restarting now.'
- self._autoReload = 0
+ self._autoReload = False
return self.shouldRestart()
# request that this file be monitored for changes
self._requests.append( fc.monitorFile(f, f) )
@@ -268,7 +274,7 @@
ImportSpy.modloader.fileList()[fe.userData])):
print '*** The file', fe.userData, 'has changed.', \
'The server is restarting now.'
- self._autoReload = 0
+ self._autoReload = False
return self.shouldRestart()
for req in self._requests:
req.cancelMonitor()
Modified: Webware/trunk/WebKit/ThreadedAppServer.py
==============================================================================
--- Webware/trunk/WebKit/ThreadedAppServer.py (original)
+++ Webware/trunk/WebKit/ThreadedAppServer.py Thu Sep 29 15:05:09 2005
@@ -179,8 +179,9 @@
This is the main thread loop that accepts and dispatches
socket requests.
- It goes through an loop as long as ``self.running`` is True
- (i.e., ``self.running = False`` asks the server to stop running).
+ It goes through an loop as long as ``self.running`` is ``True``.
+ Setting ``self.running = None`` asks the server to stop running.
+ When it has shut down, it sets ``self.running = False``.
The loop waits for connections, then based on the connecting
port it initiates the proper Handler (e.g.,
@@ -203,42 +204,48 @@
threadUpdateDivisor = 5 # grab stat interval
threadCheck = 0
- while 1:
- if not self.running:
- return
+ try:
+ while self.running:
- #block for timeout seconds waiting for connections
- try:
- input, output, exc = select.select(
- self._sockets.values(), [], [], timeout)
- except select.error, v:
- if not self.running:
- return
- input = []
- if v[0] == EINTR or v[0] == 0: break
- else: raise
-
- for sock in input:
- self._requestID += 1
- client, addr = sock.accept()
- serverAddress = sock.getsockname()
+ # block for timeout seconds waiting for connections
try:
- handler = self._handlerCache[serverAddress].pop()
- except IndexError:
- handler = self._socketHandlers[serverAddress](self, serverAddress)
- handler.activate(client, self._requestID)
- self._requestQueue.put(handler)
-
- if threadCheck % threadUpdateDivisor == 0:
- self.updateThreadUsage()
-
- if threadCheck > threadCheckInterval:
- threadCheck = 0
- self.manageThreadCount()
- else:
- threadCheck = threadCheck + 1
+ input, output, exc = select.select(
+ self._sockets.values(), [], [], timeout)
+ except select.error, v:
+ if v[0] == EINTR or v[0] == 0:
+ break
+ else:
+ raise
+
+ for sock in input:
+ self._requestID += 1
+ client, addr = sock.accept()
+ serverAddress = sock.getsockname()
+ try:
+ handler = self._handlerCache[serverAddress].pop()
+ except IndexError:
+ handler = self._socketHandlers[serverAddress](self,
+ serverAddress)
+ handler.activate(client, self._requestID)
+ self._requestQueue.put(handler)
+
+ if threadCheck % threadUpdateDivisor == 0:
+ self.updateThreadUsage()
+
+ if threadCheck > threadCheckInterval:
+ threadCheck = 0
+ self.manageThreadCount()
+ else:
+ threadCheck = threadCheck + 1
+
+ self.restartIfNecessary()
- self.restartIfNecessary()
+ self.running = False
+ except:
+ running = self.running
+ self.running = False
+ if running: # was the exception while running?
+ raise # then raise it
## Thread Management ##
@@ -360,7 +367,7 @@
# of the threads we want gone may not yet be gone.
# But we'll pick them up later -- they'll wait,.
if not i.isAlive():
- rv = i.join() #Don't need a timeout, it isn't alive
+ rv = i.join() # Don't need a timeout, it isn't alive
self._threadPool.remove(i)
if debug: print "Thread Absorbed, Real Thread Count=", len(self.threadPool)
@@ -436,25 +443,32 @@
and tells all the threads to die.
"""
- self.running = False
- self.awakeSelect()
- self._shuttingdown = False # jsl-is this used anywhere?
+ self._shuttingdown = True # see AppServer.shutDown()
+ self.running = None # ask Appserver to shut dhow
print "ThreadedAppServer: Shutting Down"
+ self.awakeSelect() # unblock select call in mainloop()
+ for i in range(30): # wait at most 3 seconds for shutdown
+ if not self.running and self.running is not None:
+ break
+ time.sleep(0.1)
+ # Close all sockets now:
for sock in self._sockets.values():
sock.close()
+ # Tell all threads to end:
for i in range(self._threadCount):
- self._requestQueue.put(None) # kill all threads
+ self._requestQueue.put(None)
for i in self._threadPool:
try:
i.join()
except:
pass
+ # Call super's shutdown:
AppServer.shutDown(self)
def awakeSelect(self):
"""Awake the select() call.
- The ``select()`` in `mainloop` is blocking, so when
+ The ``select()`` in `mainloop()` is blocking, so when
we shut down we have to make a connect to unblock it.
Here's where we do that, called `shutDown`.
@@ -841,7 +855,7 @@
t.start()
try:
while server.running:
- time.sleep(1)
+ time.sleep(1) # wait for interrupt
except KeyboardInterrupt:
pass
server.running = False
@@ -863,12 +877,13 @@
except Exception, e:
if not doesRunHandleExceptions:
raise
+ print
if not isinstance(e, SystemExit):
import traceback
traceback.print_exc(file=sys.stderr)
- print "\nExiting AppServer due to above exception"
+ print "Exiting AppServer due to above exception"
else:
- print "\nExiting AppServer due to sys.exit()"
+ print "Exiting AppServer due to sys.exit()"
if server:
if server.running:
server.initiateShutdown()
@@ -888,8 +903,8 @@
global server
print
print "AppServer received signal", signum
- print "Shutting down at", time.asctime(time.localtime(time.time()))
- if server:
+ if server and server.running:
+ print "Shutting down at", time.asctime(time.localtime(time.time()))
server.initiateShutdown()
else:
print 'WARNING: No server reference to shutdown.'
|