[python-win32] unexpected behavior for threaded Windows Service

Jim Vickroy Jim.Vickroy at noaa.gov
Tue Sep 21 17:41:39 CEST 2004


Attached is a "short" script that demonstrates an unexpected behavior of a
threaded, producer/consumer, Windows Service.

My expectation was that the producer would be queuing events every 2
(producer_pause) seconds while the consumer would be processing queued
events every 10 (consumer_pause) seconds.  However, the log, generated by
this Service, indicates the producer is queuing events at the same frequency
as the consumer is processing them.

Could someone help me to understand why the producer is not operating
independently of the consumer?


Thanks,

-- jv


P.S.

My system:
	Python 2.3.3
	pywin build 202
	Windows XP
-------------- next part --------------
'''
A MSW  Service with a producer and a consumer thread connected by a queue.

AUTHOR
   jim.vickroy at noaa.gov
'''


import win32serviceutil, win32service, win32event
import Queue
from   thread  import start_new_thread
from   logging import getLogger, shutdown, Logger, FileHandler, Formatter, CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET
from   time    import ctime, sleep, time




class Tester(win32serviceutil.ServiceFramework):

   _svc_name_         = 'Threaded.Services.Tester'
   _svc_display_name_ = _svc_name_.replace('.', ' ')
   _svc_deps_         = ['EventLog'] # optional -- names of services to be started before this one

   consumer_pause = 10 # seconds
   producer_pause =  2 # seconds


   def __init__(self, args):

      win32serviceutil.ServiceFramework.__init__(self, args)

      # create/configure a logger to record service activities ...
      self.log        = getLogger(self._svc_display_name_)
      filename  = '%s.log' % self._svc_display_name_
      recorder  = FileHandler(filename)
      formatter = Formatter('%(asctime)s, %(levelname)-8s, %(message)s')
      recorder.setLevel(DEBUG)
      recorder.setFormatter(formatter)
      self.log.addHandler(recorder)
      self.log.setLevel(DEBUG)

      # remaining infrastructure attributes ...
      self.stop_request = win32event.CreateEvent(None, 0, 0, None) # "stop" request
      self.events       = Queue.Queue() # events to be processed


   def SvcStop(self):

      self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) # send an acknowledgement to the SCM
      win32event.SetEvent(self.stop_request)


   def SvcDoRun(self):

      start_new_thread(self.producer, ()) # no parameters to pass to the procedure

      import servicemanager # available only at runtime
      servicemanager.LogInfoMsg('%s started' % self._svc_display_name_) # record event in Microsoft Windows Application Events Log

      while not self.shutdown_requested():
         while not self.events.empty():
            event = self.events.get()
            self.log.info('consumed "%s"' % event)

      self.shut_down()


   def shut_down(self):

      import servicemanager # available only at runtime
      servicemanager.LogInfoMsg('%s stopped' % self._svc_display_name_) # record event in Microsoft Windows Application Events Log
      self.log.info('SHUTDOWN request received')
      shutdown()


   def shutdown_requested(self):

      return win32event.WaitForSingleObject(self.stop_request, self.consumer_pause * 1000) == win32event.WAIT_OBJECT_0


   def producer(self):

      while not self.shutdown_requested():
         event = ctime(time())
         try:
            self.events.put(event)
         except Exception, details:
            self.log.exception('events queuing failure')
         else:
            self.log.info('queued   "%s"' % event)
         sleep(self.producer_pause)




if __name__=='__main__':
   from win32serviceutil import HandleCommandLine
   HandleCommandLine(Tester)


More information about the Python-win32 mailing list