[Zope-Checkins] CVS: Zope/lib/python - Lifetime.py:1.2.4.3
Toby Dickenson
tdickenson@geminidataloggers.com
Tue, 31 Dec 2002 07:10:08 -0500
Update of /cvs-repository/Zope/lib/python
In directory cvs.zope.org:/tmp/cvs-serv18908/lib/python
Added Files:
Tag: Zope-2_6-branch
Lifetime.py
Log Message:
implemented Brians proposal for a getClientAddr method
=== Zope/lib/python/Lifetime.py 1.2.4.2 => 1.2.4.3 ===
--- /dev/null Tue Dec 31 07:10:08 2002
+++ Zope/lib/python/Lifetime.py Tue Dec 31 07:09:37 2002
@@ -0,0 +1,81 @@
+import sys, asyncore, time
+
+_shutdown_phase = 0
+_shutdown_timeout = 30 # seconds per phase
+
+# The shutdown phase counts up from 0 to 4.
+#
+# 0 Not yet terminating. running in main loop
+#
+# 1 Loss of service is imminent. Prepare any front-end proxies for this happening
+# by stopping any ICP servers, so that they can choose to send requests to other
+# Zope servers in the cluster.
+#
+# 2 Stop accepting any new requests.
+#
+# 3 Wait for all old requests to have been processed
+#
+# 4 Already terminated
+#
+# It is up to individual socket handlers to implement these actions, by providing the
+# 'clean_shutdown_control' method. This is called intermittantly during shutdown with
+# two parameters; the current phase number, and the amount of time that it has currently
+# been in that phase. This method should return true if it does not yet want shutdown to
+# proceed to the next phase.
+
+def shutdown(exit_code,fast = 0):
+ global _shutdown_phase
+ global _shutdown_timeout
+ if _shutdown_phase == 0:
+ # Thread safety? proably no need to care
+ sys.ZServerExitCode = exit_code
+ _shutdown_phase = 1
+ if fast:
+ # Someone wants us to shutdown fast. This is hooked into SIGTERM - so possibly
+ # the system is going down and we can expect a SIGKILL within a few seconds.
+ # Limit each shutdown phase to one second. This is fast enough, but still clean.
+ _shutdown_timeout = 1.0
+
+def loop():
+ # Run the main loop until someone calls shutdown()
+ lifetime_loop()
+ # Gradually close sockets in the right order, while running a select
+ # loop to allow remaining requests to trickle away.
+ graceful_shutdown_loop()
+
+def lifetime_loop():
+ # The main loop. Stay in here until we need to shutdown
+ map = asyncore.socket_map
+ timeout = 30.0
+ while map and _shutdown_phase == 0:
+ asyncore.poll(timeout, map)
+
+
+def graceful_shutdown_loop():
+ # The shutdown loop. Allow various services to shutdown gradually.
+ global _shutdown_phase
+ timestamp = time.time()
+ timeout = 1.0
+ map = asyncore.socket_map
+ while map and _shutdown_phase < 4:
+ time_in_this_phase = time.time()-timestamp
+ veto = 0
+ for fd,obj in map.items():
+ try:
+ fn = getattr(obj,'clean_shutdown_control')
+ except AttributeError:
+ pass
+ else:
+ try:
+ veto = veto or fn(_shutdown_phase,time_in_this_phase)
+ except:
+ obj.handle_error()
+ if veto and time_in_this_phase<_shutdown_timeout:
+ # Any open socket handler can veto moving on to the next shutdown phase.
+ # (but not forever)
+ asyncore.poll(timeout, map)
+ else:
+ # No vetos? That is one step closer to shutting down
+ _shutdown_phase += 1
+ timestamp = time.time()
+
\ No newline at end of file