Commit 65974195 authored by Jeremy Hylton's avatar Jeremy Hylton

Refactored, but untested.

Refactor the main SvcDoRun() method to make it a little easier to
read.  Move the details of log messages to helper methods.  Trim
comments that explain obvious code.

Make log messages read the same as zdaemon log messages.
parent ef94ba5c
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
# #
############################################################################## ##############################################################################
""" Windows NT/2K service installer/controller for Zope/ZEO/ZRS instance """Windows Services installer/controller for Zope/ZEO/ZRS instance homes"""
homes """
import win32serviceutil import win32serviceutil
import win32service import win32service
...@@ -74,10 +73,35 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -74,10 +73,35 @@ class Service(win32serviceutil.ServiceFramework):
None, cmd, None, None, 0, 0, None, None, None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO()) win32process.STARTUPINFO())
def logmsg(self, event):
# log a service event using servicemanager.LogMsg
from servicemanager import LogMsg
LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, event,
(self._svc_name_, " (%s)" % self._svc_display_name_))
def info(self, s):
from servicemanager import LogInfoMsg
LogInfoMsg("%s (%s): %s" %
(self._svc_name_, self._svc_display_name_, s))
def warning(self, s):
from servicemanager import LogWarningMsg
LogWarningMsg("%s (%s): %s" %
(self._svc_name_, self._svc_display_name_, s))
def error(self, s):
from servicemanager import LogErrorMsg
LogErrorMsg("%s (%s): %s" %
(self._svc_name_, self._svc_display_name_, s))
def SvcDoRun(self): def SvcDoRun(self):
# indicate to Zope that the process is daemon managed (restartable) # indicate to Zope that the process is daemon managed (restartable)
os.environ['ZMANAGED'] = '1' os.environ['ZMANAGED'] = '1'
# XXX the restart behavior is different here than it is for
# zdaemon.zdrun. we should probably do the same thing in both
# places.
# daemon behavior: we want to to restart the process if it # daemon behavior: we want to to restart the process if it
# dies, but if it dies too many times, we need to give up. # dies, but if it dies too many times, we need to give up.
...@@ -96,24 +120,14 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -96,24 +120,14 @@ class Service(win32serviceutil.ServiceFramework):
backoff_cumulative = 0 backoff_cumulative = 0
import servicemanager import servicemanager
self.logmsg(servicemanager.PYS_SERVICE_STARTED)
# log a service started message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ' (%s)' % self._svc_display_name_))
while 1: while 1:
start_time = time.time() start_time = time.time()
info = self.createProcess(self.start_cmd) info = self.createProcess(self.start_cmd)
self.hZope = info[0] # the pid self.hZope = info[0] # the pid
if backoff_interval > BACKOFF_INITIAL_INTERVAL: if backoff_interval > BACKOFF_INITIAL_INTERVAL:
# if we're in a backoff state, log a message about self.info("created process")
# starting a new process
servicemanager.LogInfoMsg(
'%s (%s): recovering from died process, new process '
'started' % (self._svc_name_, self._svc_display_name_)
)
rc = win32event.WaitForMultipleObjects( rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE) (self.hWaitStop, self.hZope), 0, win32event.INFINITE)
if rc == win32event.WAIT_OBJECT_0: if rc == win32event.WAIT_OBJECT_0:
...@@ -129,51 +143,26 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -129,51 +143,26 @@ class Service(win32serviceutil.ServiceFramework):
# interface (or it otherwise exited cleanly) # interface (or it otherwise exited cleanly)
break break
else: else:
# this was an abormal shutdown. if we can, we want to # this was an abormal shutdown.
# restart the process but if it seems hopeless,
# don't restart an infinite number of times.
if backoff_cumulative > BACKOFF_MAX: if backoff_cumulative > BACKOFF_MAX:
# it's hopeless self.error("restarting too frequently; quit")
servicemanager.LogErrorMsg(
'%s (%s): process could not be restarted due to max '
'restart attempts exceeded' % (
self._svc_display_name_, self._svc_name_
))
self.SvcStop() self.SvcStop()
break break
servicemanager.LogWarningMsg( self.warning("sleep %s to avoid rapid restarts"
'%s (%s): process died unexpectedly. Will attempt ' % backoff_interval)
'restart after %s seconds.' % (
self._svc_name_, self._svc_display_name_,
backoff_interval
)
)
# if BACKOFF_CLEAR_TIME seconds have elapsed since we last
# started the process, reset the backoff interval
# and the cumulative backoff time to their original
# states
if time.time() - start_time > BACKOFF_CLEAR_TIME: if time.time() - start_time > BACKOFF_CLEAR_TIME:
backoff_interval = BACKOFF_INITIAL_INTERVAL backoff_interval = BACKOFF_INITIAL_INTERVAL
backoff_cumulative = 0 backoff_cumulative = 0
# we sleep for the backoff interval. since this is async # XXX Since this is async code, it would be better
# code, it would be better done by sending and # done by sending and catching a timed event (a
# catching a timed event (a service # service stop request will need to wait for us to
# stop request will need to wait for us to stop sleeping), # stop sleeping), but this works well enough for me.
# but this works well enough for me.
time.sleep(backoff_interval) time.sleep(backoff_interval)
# update backoff_cumulative with the time we spent backoff_cumulative += backoff_interval
# backing off. backoff_interval *= 2
backoff_cumulative = backoff_cumulative + backoff_interval
# bump the backoff interval up by 2* the last interval
backoff_interval = backoff_interval * 2
# loop and try to restart the process
# log a service stopped message self.logmsg(servicemanager.PYS_SERVICE_STOPPED)
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ' (%s) ' % self._svc_display_name_))
if __name__=='__main__': if __name__ == '__main__':
win32serviceutil.HandleCommandLine(Service) win32serviceutil.HandleCommandLine(Service)
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