2017-08-03 57 views
0

我正在開發一個Windows服務來監視控制系統的信號。我用兩個類(IOSignal和Control)模擬了系統。每個Control實例都有一些與之關聯的IOSignals實例。當與特定控件關聯的所有IOSignals都處於特定狀態時,我希望該服務能夠執行某些操作。在我的真實代碼中,它將在數據庫中註冊這個事件。爲了解釋我的問題,我創建了一個非常簡化的版本,我的原始代碼。 問題是,當它作爲服務運行時,我想存儲所有Control和IOSignal實例的狀態,因此當我重新啓動服務時,我可以「記住」系統停止時的狀態。我正在使用泡菜來做到這一點。似乎酸洗部分正在工作,顯然我可以在另一個腳本中打開文件並檢索我的對象的信息。 我係統的複雜性在於,我在每個Control對象中都存儲了IOSignals實例,反之亦然。 當我明星的服務似乎工作正常,但當我重新啓動它,我開始接收錯誤消息,重新創建的對象沒有一些屬性(主要是'd'和'記錄器') 我有覆蓋getstaesetstate嘗試做酸菜的方法,但我認爲我錯過了一些東西。我跟着這條巨蟒文檔中給出的說明(https://docs.python.org/2.0/lib/pickle-example.html複雜類Python醃菜

這裏是我的類的代碼(我將它們保存在一個名爲Observer.py文件)

# -*- coding: utf-8 -*- 
""" 
Created on Wed Aug 2 11:07:28 2017 

@author: me 
""" 
from logging import getLogger 
#import logging 

class IOSignal(object): 

    def __init__(self,tag,val='True'): 
     self.tag=tag 
     self.value=val 
     self.CONTROLS=[] 

     #logger 
     self.logger=getLogger('teste.IOSignals') 

     # dict to serialize 
     self.d={} 
     self.d['tag']=self.tag 
     self.d['value']=self.value 
     self.d['CONTROLS']=self.CONTROLS 

    def getTag(self): 
     return self.tag 

    def getValue(self): 
     return self.value 

    def UpdateIOSinal(self,val): 
     self.value=val 
     try: 
      for control in self.CONTROLS: 
       #self.logger.debug('updating controls') 
       control.update() 
     except Exception as e: 
       self.logger.error("Error updating signal - ErrMsg -> {}".format(str(e))) 

    def AppendControl(self,control): 
     self.CONTROLS.append(control) 

    def UpdateControls(self): 
     for control in self.CONTROLS: 
      control.update() 

    def __getstate__(self): 
     return self.d 

    def __setstate__(self, d): 
     self.tag=d['tag'] 
     self.value=d['value'] 
     self.CONTROLS=d['CONTROLS'] 
     self.__dict__= d 


class Control(object): 

    def __init__(self,tag,state=False): 
     self.tag=tag 
     self.state=state 
     self.IOSignals={} 

     #logger 
     self.logger=getLogger('teste.CONTROLS') 

     # dict to serialize 
     self.d={} 
     self.d['tag']=self.tag 
     self.d['state']=self.state 
     self.d['IOSignals']=self.IOSignals 


    def getTag(self): 
     return self.tag 

    def getState(self): 
     return self.state 

    def register_signal(self,signal): 
     self.IOSignals[len(self.IOSignals)]=signal 

    def update(self): 
     try: 
      I=len([e.value for e in self.IOSignals.values() if e.value=='False']) 
      if I==len(self.IOSignals): 
       self.logger.info("Control {} actuated".format(self.tag)) 
     except Exception as e: 
       self.logger.error("Error updating Contro - ErrMsg -> {}".format(str(e))) 

    def __getstate__(self): 
     return self.d 

    def __setstate__(self, d): 
     self.tag=d['tag'] 
     self.state=d['state'] 
     self.IOSignals=d['IOSignals'] 

     self.__dict__= d  

,這裏是創建代碼服務和使用Observer。我把它叫做teste_service.py 來安裝它,在命令行中輸入以下命令「python c:\ pathtofile \ teste_service.py install」,並將它放在Windows服務中運行。 服務的名稱是TEST_Event_Service。

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

@author: me 
""" 

from Observer import IOSignal 
from Observer import Control 
import os 
import threading 
import logging 
import logging.config 
import win32api 
import win32service 
import win32serviceutil 
import win32event 
import random 
import time 
import pickle 

class InterruptedException(Exception): 
    pass 

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

     self.dCONFIG=dCONFIG 
     self.dIO=dCONFIG['dIO'] 
     self.dCTRL=dCONFIG['dCTRL'] 

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

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

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

    def saveCACHE(self): 
     try: 
      f=open(r'C:\TIER3\teste\teste.pkl','wb') 
      pickle.dump(self.dCONFIG,f,protocol=4) 
      f.close() 
     except Exception as e: 
      self.logger.error("Error saving cache - ErrMsg -> {}".format(str(e))) 

    def getCONFIG(self): 
     return self.dCONFIG 

    def run(self): 
     try: 
      # simulater signal state based on a random number generator 
      for signal in self.dIO.values(): 
       r=random.random() 
       if r>0.5: 
        signal.UpdateIOSinal('False') 
       else: 
        signal.UpdateIOSinal('True') 

      #updating dCONFIG to pickle it 
      self.dCONFIG['dIO']=self.dIO 
      self.dCONFIG['dCTRL']=self.dCTRL 

      try: 
       self.saveCACHE() 
      except Exception as e: 
       self.logger.error("Error saving cache - ErrMsg -> {}".format(str(e))) 

      #self.logger.info('run finished') 
      time.sleep(10) 
     except InterruptedException as e: 
      # We are forcefully quitting 
      self.logger.error('Interruption Exception - {}'.format(str(e))) 
      pass 
     except Exception as e: 
      self.logger.error('Unexpected Error - {}'.format(str(e))) 
      #self.logger.error(e) 
      pass 
      # Oh oh, did not anticipate this, better report to Windows or log it 
     finally: 
      #pass 
      # 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) 
     self.dCONFIG={} 
     #------------------------------------------------------------------------------ 
     # Creating logger 
     #------------------------------------------------------------------------------ 
     logging.config.fileConfig(r'c:\tier3\teste\teste_logging.conf') 
     # create logger 
     self.logger = logging.getLogger('teste') 

     self.logger.info(self._svc_name_ + " - STARTED!") 
     #creating some IOSignals and Controls 
     dIO={} 
     dCTRL={} 
     try: 
      if os.path.exists(r'C:\TIER3\teste\teste.pkl'): 
       f=open(r'C:\TIER3\teste\teste.pkl','rb') 
       self.dCONFIG=pickle.load(f) 
       dIO=self.dCONFIG['dIO'] 
       dCTRL=self.dCONFIG['dCTRL'] 
       f.close()    
      else: 
       dIO[1]=IOSignal('IO1') 
       dIO[2]=IOSignal('IO2') 
       dIO[3]=IOSignal('IO3') 
       dIO[4]=IOSignal('IO4') 
       dIO[5]=IOSignal('IO5') 
       dIO[6]=IOSignal('IO6') 
       dIO[7]=IOSignal('IO7')   
       dIO[8]=IOSignal('IO8') 

       dCTRL[1]=Control('CTRL1') 
       dCTRL[2]=Control('CTRL2') 
       dCTRL[3]=Control('CTRL3') 
       dCTRL[4]=Control('CTRL4') 

       dIO[1].AppendControl(dCTRL[1]) 
       dIO[2].AppendControl(dCTRL[1]) 
       dIO[3].AppendControl(dCTRL[2]) 
       dIO[4].AppendControl(dCTRL[2]) 
       dIO[5].AppendControl(dCTRL[3]) 
       dIO[6].AppendControl(dCTRL[3]) 
       dIO[7].AppendControl(dCTRL[4]) 
       dIO[8].AppendControl(dCTRL[4]) 

       dCTRL[1].register_signal(dIO[1]) 
       dCTRL[1].register_signal(dIO[2]) 
       dCTRL[2].register_signal(dIO[3]) 
       dCTRL[2].register_signal(dIO[4]) 
       dCTRL[3].register_signal(dIO[5]) 
       dCTRL[3].register_signal(dIO[6]) 
       dCTRL[4].register_signal(dIO[7]) 
       dCTRL[4].register_signal(dIO[8]) 

       self.dCONFIG={} 
       self.dCONFIG['dIO']=dIO 
       self.dCONFIG['dCTRL']=dCTRL 

     except Exception as e: 
      self.logger.error("Error opening teste.pkl - ErrMsg -> {}".format(str(e))) 

    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_, '')) 

     #create worker 1st run 
     self.worker = WorkerThread(self.hWaitDone,self.dCONFIG) 
     self.worker.setDaemon=True 
     self.worker.start() 

     while True: 
      rc = win32event.WaitForMultipleObjects([self.hWaitStop, self.hWaitDone],False,win32event.INFINITE) 
      #self.logger.debug('rc = {}'.format(rc)) 
      # Check to see if self.hWaitStop happened as part of Windows Service Management 
      if rc == 0: 
       # Stop signal encountered 
       self.logger.info(self._svc_name_ + " - STOPPED!") 
       servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!") #For Event Log 
       break 
      if rc == 1: 
       #create worker 
       self.dCONFIG=self.worker.getCONFIG() 
       self.worker = WorkerThread(self.hWaitDone,self.dCONFIG) 
       self.worker.setDaemon=True 
       self.worker.start() 

def ctrlHandler(ctrlType): 
    return True 

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

這裏是日誌設置

[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:\tier3\teste\pyteste.log','a',5000000,20) 
formatter=logfileformatter 

我認爲我的問題是在,有getstatesetstate這定義。

這裏是我收到的錯誤消息的示例。

2017-08-02 22:58:00,348 teste.SERVICE: ERROR Error saving cache - ErrMsg -> 'IOSignal' object has no attribute 'd' 
2017-08-02 22:58:10,366 teste.SERVICE: ERROR Unexpected Error - 'IOSignal' object has no attribute 'logger' 

任何人都有一些ideia我的問題在哪裏?

+0

有很多事情不能被醃製。這可能是發生了什麼 – Zizouz212

+0

是的。我知道,但如果在python控制檯中取消選中文件,我可以看到類的結構被檢索到。我可以調用方法並訪問實例屬性。但是,在某種程度上,重構實例並不完整,有些項目被拋在後面。 – Dariva

+0

更改爲'self .__ dict __。update(d)'。 – stovfl

回答

0

我設法找到一個不合我願意的解決方案。由於實例未完全重新創建,因此每次運行服務時都會創建所有實例,並檢查是否存在緩存文件。如果有我使用緩存中的信息調整實例狀態。這裏是Observer.py的修改代碼。我創建了新的方法來設置我需要的值。