2012-02-28 144 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可能很難合作。

謝謝大家