2012-02-28 155 views
2

我有一个简单的Windows服务,我使用python创建。我的问题是,我不知道服务需要多长时间才能完成,可能需要15秒,也可能需要4个小时以上,这取决于数据需要做什么。 4个小时以上是一种罕见的情况,但是我遇到过这种情况。长时间运行的进程超时和Windows服务(Python)

下面是我一直关注的Windows服务的一般模式。我拿出了所有的逻辑,但这不是问题,只留下了伪日志记录命令。有没有办法阻止服务继续或不刷新,直到逻辑部分完成而不是使用超时?

import win32service 
import win32serviceutil 
import win32api 
import win32con 
import win32event 
import win32evtlogutil 
import os 
import sys 
import time 
import logging 
class aservice(win32serviceutil.ServiceFramework): 
    _svc_name_ = "WeatherService" 
    _svc_display_name_ = "Weather Service" 
    _svc_description_ = "Downloads weather data from NOAA and creates maps" 
    def __init__(self, args): 
     win32serviceutil.ServiceFramework.__init__(self, args) 
     self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)   
    def SvcStop(self): 
     self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
     win32event.SetEvent(self.hWaitStop)      
    def SvcDoRun(self): 
     import servicemanager  
     servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, 
           servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 
     self.timeout = 640000 #640 seconds/10 minutes (value is in milliseconds) 
     #self.timeout = 120000  #120 seconds/2 minutes 
     # This is how long the service will wait to run/refresh itself (see script below) 
     while 1: 
      # Wait for service stop signal, if I timeout, loop again 
      rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout) 
      # Check to see if self.hWaitStop happened 
      if rc == win32event.WAIT_OBJECT_0: 
       # Stop signal encountered 
       servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!") #For Event Log 
       break 
      else: 
       #[actual service code between rests] 
       try: 
        logging.basicConfig(filename=r"c:\temp\example.log",level=logging.DEBUG, 
             format='%(asctime)s %(message)s') 
        logging.debug('This message should go to the log file') 
        logging.info('So should this') 
        logging.warning('And this, too') 

        #file_path = "C:\whereever\my_REAL_py_work_to_be_done.py" 
        #execfile(file_path)    #Execute the script 
        #inc_file_path2 = "C:\whereever\MORE_REAL_py_work_to_be_done.py" 
        #execfile(inc_file_path2)  #Execute the script 
       except: 
        pass 
       #[actual service code between rests] 


def ctrlHandler(ctrlType): 
    return True 

if __name__ == '__main__': 
    win32api.SetConsoleCtrlHandler(ctrlHandler, True) 
    win32serviceutil.HandleCommandLine(aservice) 

回答

0

你可以开始一个新的过程来做长期的事情。如果停止信号到达,您终止子进程。

+0

当我将超时设置为无限的,它永远不会移过RS = win32event.WaitForSingleObject()。那么我应该如何创建停止信号/回路以允许无限的时间? – 2012-02-28 19:30:30

0

将该服务用作具有多个线程的控制器。 一个线程(Main)应该同步并排队命令,并使用win32服务框架进行通信,注册到系统等。 另一个线程(Worker)应该等待队列中的命令并执行它们。如果您将任意代码作为单独的进程执行,那么您可以从工作线程产生这些代码,并在完成并清理后简单地回读结果。

这样,当停止到达时,主线程会将其注册到其队列中的工作器,该工作器将被唤醒并尝试指示其他进程退出,等待一会并清理或终止它们有力地。

更新:

下面是你如何能有一个服务,它总是反应灵敏,只要需要运行一个样品的概念。每个工人可以抛出

... 
import threading 
... 

class InterruptedException(Exception): 
    pass 

class WorkerThread(threading.Thread): 
    def __init__(self, controller): 
     self._controller = controller 
     self._stop = threading.Event() 
     super(WorkerThread, self).__init__() 

    def stop(self): 
     self._stop.set() 

    def stopped(self): 
     return self._stop.isSet() 

    def run(self): 
     try: 
      # Insert the code you want to run as a service here 
      # rather than do "execfile(.../.../blah)" simply do: 
      # You can have your code throw InterruptedException if your code needs to exit 
      # Also check often if self.stopped and then cleanly exit 

      import your_file 
      your_file.main() 

      # if code in another module is not yours or cannot check often if it should stop then use multiprocessing which will spawn separate processes that you can terminate then from here when you need to stop and return 
      # in that case simply block here on self._stop.wait() 

     except InterruptedException as exc: 
      # We are forcefully quitting 
      pass 
     except Exception as e: 
      # Oh oh, did not anticipate this, better report to Windows or log it 
     finally: 
      # Close/release any connections, handles, files etc. 

      # OK, we can stop now 
      win32event.SetEvent(self._controller) 

def __init__(self, args): 
    win32serviceutil.ServiceFramework.__init__(self, args) 
    self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)  
    self.hWaitDone = win32event.CreateEvent(None, 0, 0, None) 

def SvcDoRun(self): 
    import servicemanager  
    servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, 
          servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 

    worker = WorkerThread(self.hWaitDone) 
    worker.start() 

    while True: 
     # Wait for service stop signal 
     rc = win32event.WaitForMultipleObjects([self.hWaitStop, self.hWaitDone], win32event.INFINITE) 

     # Check to see if self.hWaitStop happened as part of Windows Service Management 
     if rc == 0: 
      # Stop signal encountered 
      servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!") #For Event Log 
      break 

     if rc == 1: 
      # Wait until worker has fully finished 
      worker.join() 

      # Determine from worker state if we need to start again (because run finished) 
      # Or do whatever 
      if not worker.need_to_start_again(): 
       break 

      worker.start() 
+0

我明白停止线程等的概念,但如果我使用这个:rc = win32event.WaitForSingleObject(self.hWaitStop,self.timeout)其中self.timeout是几秒钟内的某个值,我发现该服务有时会超时,但我不希望它。我不知道总处理时间。如果我从self.timeout更改为win32event.INFINITE,则它不起作用 – 2012-02-28 15:59:49

+0

请参阅上面关于如何重构以消除超时需求的更新。 – astevanovic 2012-02-29 01:32:48

+0

看来,服务永远不会超越这里: #等待服务停止信号 rc = win32event.WaitForMultipleObjects([self.hWaitStop,self.hWaitDone],win32event.INFINITE)。当我观看这项服务时,即使只是写入文件等最基本的事情,也会崩溃。 – 2012-02-29 11:58:09

0

我结束了使用这种模式:http://code.activestate.com/recipes/551780/

它运作良好,但不是像一个魅力。我确实遇到多处理问题,这个过程不会产生实例。对此的建议?

请继续发布您的答案,我想看到每个人的解决方案,因为win32api可能很难合作。

谢谢大家