2012-02-28 55 views
2

私はPythonを使用して作成した簡単なWindowsサービスを持っています。私の問題は、サービスの完了までにどれくらいの時間がかかるかわからないということです。データの処理には15秒かかり、4時間以上かかることがあります。 4時間以上はまれですが、これが起こる状況があります。長時間実行されるプロセス(Python)のタイムアウトとWindowsサービス

以下は、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

ありがとうございます。ですから、無限の時間を取るために停止信号/ループをどのように作りますか? –

0

このサービスは、複数のスレッドを持つコントローラとして使用します。 1つのスレッド(Main)は、コマンドを同期させて待ち行列に入れ、通信やシステムへの登録などのためにwin32 serviceframeworkを使用します。 別のスレッド(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に変更した場合、どちらも動作しません –

+0

上記のタイムアウトに頼る必要をなくすための再構成方法の更新を参照してください。 – astevanovic

+0

サービスはここを超えていないようです: #サービス停止信号を待ちます rc = win32event.WaitForMultipleObjects([self.hWaitStop、self.hWaitDone]、win32event.INFINITE)。私がサービスを見ると、ただファイルに書き込むような最も基本的なことをしても、クラッシュします。 –

0

をスローすることが、私はこのパターンを使用して終了:http://code.activestate.com/recipes/551780/

それはうまく動作しますが、魅力を好きではありません。私はプロセスがインスタンスを生成していないマルチプロセッシングに関する問題があります。それについての示唆?

あなたの回答を投稿し続けてください。私はwin32apiがうまく動作しない可能性があるので、みんなのソリューションを見たいと思います。

は、私が無限にタイムアウトを設定すると、それは)、RS = win32event.WaitForSingleObject(通り過ぎることはありませんみんな

関連する問題