Commit 09113090 authored by Vincent Pelletier's avatar Vincent Pelletier

Define, handle and advertise shutdown_method option.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@22387 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 705896e0
...@@ -39,6 +39,13 @@ wait_for_close_lock = thread.allocate_lock() ...@@ -39,6 +39,13 @@ wait_for_close_lock = thread.allocate_lock()
class ClockServer(OriginalClockServer): class ClockServer(OriginalClockServer):
running = True running = True
def __init__(self, *args, **kw):
self.shutdown_method = kw.pop('shutdown_method')
OriginalClockServer.__init__(self, *args, **kw)
if self.shutdown_method is None:
self.log_info('ClockServer shutdown_method is not set in configuration'\
'file. Unclean shutdown can happen.', type='warning')
def readable(self): def readable(self):
""" """
Avoid starting a new tic if shutdown started. Avoid starting a new tic if shutdown started.
...@@ -73,31 +80,29 @@ class ClockServer(OriginalClockServer): ...@@ -73,31 +80,29 @@ class ClockServer(OriginalClockServer):
closed. closed.
""" """
self.running = False self.running = False
separator = '?' in self.method and '&' or '?' if self.shutdown_method is not None:
# XXX: should use a float for time representation # XXX: should use a float for time representation
# TODO: allow user to specify a separate shutdown method instead of method = '%s?phase:int=%i&time_in_phase:float=%f' % \
# reusing regular one. (self.shutdown_method, _shutdown_phase, time_in_this_phase)
method = '%s%sshutdown:int=1&phase:int=%i&time_in_phase:int=%i' % \
(self.method, separator, _shutdown_phase, time_in_this_phase)
stdin = StringIO.StringIO() stdin = StringIO.StringIO()
request_string = 'GET %s HTTP/1.0' % (method, ) request_string = 'GET %s HTTP/1.0' % (method, )
request = http_request(DummyChannel(self), request_string, 'GET', method, request = http_request(DummyChannel(self), request_string, 'GET', method,
'1.0', self.headers) '1.0', self.headers)
environment = self.get_env(request) environment = self.get_env(request)
response = make_response(request, environment) response = make_response(request, environment)
# Hook response._finish to get a notification when request is over. # Hook response._finish to get a notification when request is over.
def _finish(): def _finish():
response.__class__._finish(response) response.__class__._finish(response)
wait_for_close_lock.release()
response._finish = _finish
# (end of hook)
zope_request = HTTPRequest(stdin, environment, response)
wait_for_close_lock.acquire()
self.zhandler('Zope2', zope_request, response)
self.log_info('ClockServer: Waiting for shutdown handler.')
wait_for_close_lock.acquire()
self.log_info('ClockServer: Going on.')
wait_for_close_lock.release() wait_for_close_lock.release()
response._finish = _finish
# (end of hook)
zope_request = HTTPRequest(stdin, environment, response)
wait_for_close_lock.acquire()
self.zhandler('Zope2', zope_request, response)
self.log_info('ClockServer: Waiting for shutdown handler.')
wait_for_close_lock.acquire()
self.log_info('ClockServer: Going on.')
wait_for_close_lock.release()
return 0 # TODO: detect an error to allow taking the veto. return 0 # TODO: detect an error to allow taking the veto.
...@@ -29,6 +29,7 @@ ERP5 users: You are strongly encouraged to kee TimerService (but to stop using ...@@ -29,6 +29,7 @@ ERP5 users: You are strongly encouraged to kee TimerService (but to stop using
timerserver) and use the following configuration: timerserver) and use the following configuration:
method /Control_Panel/timer_service/process_timer?interval:int=5 method /Control_Panel/timer_service/process_timer?interval:int=5
shutdown_method /Control_Panel/timer_service/process_shutdown
period 5 period 5
Note: Because ClockServer uses asyncore's "readable" method polling, Note: Because ClockServer uses asyncore's "readable" method polling,
......
...@@ -9,6 +9,19 @@ ...@@ -9,6 +9,19 @@
method, etc). The method must take no arguments. Ex: "/site/methodname" method, etc). The method must take no arguments. Ex: "/site/methodname"
</description> </description>
</key> </key>
<key name="shutdown_method" datatype="string">
<description>
The traversal path (from the Zope root) to an
executable Zope method (Python Script, external method, product
method, etc). The method must take the following arguments:
phase (number)
Shutdown phase number.
See Lifetime.py .
time_in_phase (number)
Time spent in current phase, in seconds.
Given method path must not contain any argument. Ex: "/site/methodname"
</description>
</key>
<key name="period" datatype="integer" default="60"> <key name="period" datatype="integer" default="60">
<description> <description>
The number of seconds between each clock "tick" (and The number of seconds between each clock "tick" (and
......
...@@ -18,6 +18,7 @@ class ClockServerFactory(ServerFactory): ...@@ -18,6 +18,7 @@ class ClockServerFactory(ServerFactory):
def __init__(self, section): def __init__(self, section):
ServerFactory.__init__(self) ServerFactory.__init__(self)
self.method = section.method self.method = section.method
self.shutdown_method = section.shutdown_method
self.period = section.period self.period = section.period
self.user = section.user self.user = section.user
self.password = section.password self.password = section.password
...@@ -28,5 +29,6 @@ class ClockServerFactory(ServerFactory): ...@@ -28,5 +29,6 @@ class ClockServerFactory(ServerFactory):
from Products.ClockServer.ClockServer import ClockServer from Products.ClockServer.ClockServer import ClockServer
from ZServer.AccessLogger import access_logger from ZServer.AccessLogger import access_logger
return ClockServer(self.method, self.period, self.user, return ClockServer(self.method, self.period, self.user,
self.password, self.hostheader, access_logger) self.password, self.hostheader, access_logger,
shutdown_method=self.shutdown_method)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment