Adding server modules

This commit is contained in:
2024-01-09 10:47:51 +01:00
parent 4ed4630b8d
commit a0b5ce4c58
5 changed files with 196 additions and 1 deletions

View File

@ -47,9 +47,12 @@ class AdaptiveOrbit:
print("Initializing EPICS Channels") print("Initializing EPICS Channels")
pvs = [] pvs = []
for x in chx: for x in chx:
if ':X1' in x or ':X2' in x: if ':X1' in x:
pvs.append(PV(x.replace(':X1',':X-REF-FB'))) pvs.append(PV(x.replace(':X1',':X-REF-FB')))
pvs.append(PV(x.replace(':X1',':Y-REF-FB'))) pvs.append(PV(x.replace(':X1',':Y-REF-FB')))
elif ':X2' in x:
pvs.append(PV(x.replace(':X2',':X-REF-FB')))
pvs.append(PV(x.replace(':X2',':Y-REF-FB')))
else: else:
pvs.append(PV(x)) pvs.append(PV(x))
con = [pv.wait_for_connection(timeout=0.2) for pv in pvs] con = [pv.wait_for_connection(timeout=0.2) for pv in pvs]

View File

@ -0,0 +1,33 @@
import signal
import ServerBase
class ServerTemplate(ServerBase.ServerBase):
def __init__(self, PVroot = 'MyServer', debug = False):
self.version='1.0.0'
self.program ='Server Template'
super(ServerTemplate, self).__init__(PVroot,debug,'127.0.0.1', 5678) # last too numbers are the IP adress and port of watchdog
# connect to the individual handler, which must have the function terminate() implemented
# each handler should be their own thread to not interfere with the main process-loop
self.handler={}
def terminateSubThreads(self):
for subserver in self.handler.keys():
self.handler[subserver].terminate()
if __name__ == '__main__':
debug = True
server = ServerTemplate('SF-BC-SERVER', debug)
signal.signal(signal.SIGTERM,server.terminate)
try:
server.run()
except KeyboardInterrupt:
server.terminate(None,None)

View File

@ -0,0 +1,2 @@
from .serverbase import ServerBase
from .zmqbase import ZMQBase

91
util/serverbase.py Normal file
View File

@ -0,0 +1,91 @@
import sys
import signal
import os
import socket
import logging
import logging.handlers
from logging.handlers import RotatingFileHandler
from datetime import datetime
import time
from epics import PV
import ZMQBase
class ServerBase (ZMQBase):
def __init__(self, root = 'MyServer', debug = False, WDServer = '127.0.0.1', WDPort = 5678):
super(ServerBase,self).__init__(WDServer,WDPort)
self.debug = debug
self.root = root
self.suffix=''
if self.debug:
self.suffix='-SIMU'
self.host = socket.gethostname()
self.pid = os.getpid() # process ID
# enabling logging
self.logfilename="/sf/data/applications/BD-SERVER/%s.log" % self.root
handler = RotatingFileHandler(filename=self.logfilename,
mode='a',
maxBytes=5 * 1024 * 1024,
backupCount=1,
delay=0)
if self.debug:
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M:%S')
else:
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M:%S',
handlers=[handler,])
self.logger=logging.getLogger(self.program)
# setting up ZMQ interface
self.ZMQServerInfo(self.root,self.host,self.pid)
# individual channels of main thread
self.PVstop = PV('%s:STOP%s' % (self.root,self.suffix))
self.PVstop.value = 0
self.PVstop.add_callback(self.stop)
self.PVping = PV('%s:PING%s' % (self.root,self.suffix))
self.PVlog = PV('%s:LOG%s' % (self.root,self.suffix))
def stop(self,pvname=None,value=None,**kws):
self.logger.info('PV:STOP triggered at %s' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
if value > 0:
self.running=False
def start(self):
self.logger.info('Starting Server: %s at %s' % (self.root,datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
self.logger.info('PV Root: %s' % self.root
self.logger.info('Version: %s' % self.version)
self.logger.info('Host: %s' % self.host)
self.logger.info('PID: %d' % self.pid)
if self.debug:
self.logger.info('Debug Mode')
def run(self):
self.start()
self.running=True
while self.running:
time.sleep(1)
if self.ZMQPoll():
self.logger.info('Watchdog Server requested termination')
self.running = False
self.PVping.value = datetime.now().strftime('Last active at %Y-%m-%d %H:%M:%S')
self.terminate(None,None)
def terminate(self,signum,frame):
# stopping any sub thread with the server specific function terminateSubThreads
self.terminateSubThreads()
self.logger.info('Terminating Server at %s' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
self.ZMQPoll('quit') # informing the watchdog
print('Bunch Compressor Server is quitting...')
sys.exit(0)

66
util/zmqbase.py Normal file
View File

@ -0,0 +1,66 @@
import zmq
import socket
import sys
class ZMQBase:
def __init__(self, host='127.0.0.1',port = 5678):
self.host=host
self.port = port
self.msg={'action':'','PV':'','host':'','pid':0}
self.REQUEST_TIMEOUT = 500
self.REQUEST_RETRIES = 2
self.SERVER_ENDPOINT = "tcp://%s:%d" % (host,port)
self.serverIsOffline=False # assume that it is online
def ZMQServerInfo(self,PVroot,host,pid):
self.msg['PV']=PVroot
self.msg['host']=host
self.msg['pid']=pid
def ZMQPoll(self,tag='ping'):
self.msg['action']=tag
context = zmq.Context()
client = context.socket(zmq.REQ)
client.connect(self.SERVER_ENDPOINT)
client.send_pyobj(self.msg)
retries_left = self.REQUEST_RETRIES
while True:
if (client.poll(self.REQUEST_TIMEOUT) & zmq.POLLIN) != 0:
reply = client.recv_pyobj()
check = self.ZMQIdentifyReply(reply)
if self.serverIsOffline:
self.logger.info("Watchdog server came online")
self.serverIsOffline=False
if check:
return (reply['action'] == 'quit')
else:
self.logger.warning("Malformed reply from server")
continue
retries_left -= 1
# Socket is confused. Close and remove it.
client.setsockopt(zmq.LINGER, 0)
client.close()
if retries_left == 0:
if not self.serverIsOffline:
self.logger.info("Watchdog server seems to be offline")
self.serverIsOffline=True
return False
# Create new connection
client = context.socket(zmq.REQ)
client.connect(self.SERVER_ENDPOINT)
client.send_pyobj(self.msg)
def ZMQIdentifyReply(self,reply):
for field in ['PV','host','pid']:
if not reply[field] == self.msg[field]:
return False
return True