2017-07-28 22 views
0

我正在關注下面鏈接中提供的解決方案,以便在運行一些日子後嘗試停止它時不會以STOPPING狀態掛起的Python創建Windows服務。Python中的Windows服務

Timeout and Windows Services for Long Running Processes (Python)

我現在面臨的問題是,當我啓動該服務似乎只運行一次,並在Windows服務管理服務已全部任務禁止,所以我不能停止或重新啓動它。以下是我的代碼。我已經刪除了所有我想要執行的實際任務,並將其替換爲一個虛擬服務,該虛擬服務每次運行時將1添加到變量(x)並將其寫入日誌文件。

我會很感激任何提示試圖找到我在哪裏是我的錯誤。

# -*- coding: utf-8 -*- 
""" 
Created on Thu Jul 27 09:07:29 2017 

@author:aaaa 
""" 

import threading 
import logging 
import logging.config 
import win32api 
import win32serviceutil 
import win32event 


class InterruptedException(Exception): 
    pass 

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

     self.x=0 

     #------------------------------------------------------------------------------ 
     # Creating logger 
     #------------------------------------------------------------------------------ 
     logging.config.fileConfig(r'c:\temp\teste_logging.conf') 
     # create logger 
     self.logger = logging.getLogger('teste') 
     self.logger.debug("Serviço criado") 

    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 
      self.x+=1 
      self.logger.debug('x = {}'.format(self.x)) 

     except InterruptedException as e: 
      # We are forcefully quitting 
      self.logger.debug('Interruption Exception - {}'.format(str(e))) 
      pass 
     except Exception as e: 
      self.logger.debug('Unexpected Error - {}'.format(str(e))) 
      pass 
      # 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) 

class test_service(win32serviceutil.ServiceFramework): 

    _svc_name_ = "pyTEST" 
    _svc_display_name_ = "TEST Event service" 
    _svc_description_ = "Service to teste python service" 

    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) 

     #logger 
     self.logger=logging.getLogger('teste.SERVICE') 

     #create worker 
     self.worker = WorkerThread(self.hWaitDone) 

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

     #worker = WorkerThread(self.hWaitDone,self.dCONFIG) 
     self.worker.start() 

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

      # 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 
       self.worker.join() 

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

       self.worker.start() 

def ctrlHandler(ctrlType): 
    return True 

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

這裏是日誌記錄模塊的配置。只需將其保存在文本文件中並將其保存爲teste_logging.conf

[loggers] 
keys=root,teste 

[handlers] 
keys=logfile,consoleHandler 

[formatters] 
keys=simpleFormatter,logfileformatter 

[logger_root] 
level=DEBUG 
handlers=consoleHandler 

[logger_teste] 
level=DEBUG 
handlers=logfile 
qualname=teste 
propagate=0 

[formatter_logfileformatter] 
format=%(asctime)s %(name)-12s: %(levelname)s %(message)s 

[formatter_simpleFormatter] 
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 
datefmt= 

[handler_consoleHandler] 
class=StreamHandler 
level=DEBUG 
formatter=simpleFormatter 
args=(sys.stdout,) 

[handler_logfile] 
class=handlers.RotatingFileHandler 
level=DEBUG 
args=(r'C:\temp\pyteste.log','a',5000000,20) 
formatter=logfileformatter 
+0

'WaitForMultipleObjects'的第二個參數是一個布爾值,它決定了它是否應該等待所有對象。您錯誤地將'INFINITE'(-1)傳遞給了這個參數,這是一個真實的值,所以等待總是返回WAIT_TIMEOUT(258),除非偶然事件被設置。 – eryksun

+0

但是,如果我使用rc = win32event.WaitForSingleObject(self.hWaitStop,10000) – Dariva

+0

,也會發生這種情況您提供了一個超時時間,我假設在循環中執行其他操作,然後再次等待。如果您不想超時,請使用'win32event.WaitForMultipleObjects([self.hWaitStop,self.hWaitDone],False,win32event.INFINITE)''。 – eryksun

回答

0

我發現服務任務被禁用的原因。我忘了實現SvcStop功能。

def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    win32event.SetEvent(self.hWaitStop)  

儘管如此,它仍然只運行一次。

+0

我意識到問題在於rc(win32event.WaitForMultipleObject)返回的值是258.有誰知道這意味着什麼? – Dariva

+0

'net helpmsg 258':等待操作超時。 –

+0

......我看到eryksun已經解釋了爲什麼會發生這種情況。 –