2017-08-03 62 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的修改代码。我创建了新的方法来设置我需要的值。