docker版jxTMS使用指南:python服务动态升级

jxTMS增加了python服务的动态升级能力,整个系列的文章请查看:docker版jxTMS使用指南

最近笔者在开发一个数据采集系统,体系架构就采用了jxTMS+python,其中python主要用来做接口机,通过mqtt来接收前端设备发送的实时数据加以处理和保存,管控则通过jxTMS来做。

原本已经依托一个公有的物联云做了数据采集,所以需要逐步将各个站点迁移到新系统。但时间紧、任务急,不同的站点的不同设备又需要一个个的实现采集接口和管控功能,所以没办法整体交付,只能是一个个的来。

自然的,也就不希望每次增加一个新种类的数据采集模块和管控功能,就停机重启接口机。

所以笔者就考虑给python服务增加动态升级能力。

python本身就具备动态加载模块的能力,所以本功能其实主要就是解决如何将其融入jxTMS勾连python的能力中来。考虑到本功能虽然很实用,但较为简单,目前的时间又比较紧张,所以就暂不打包到docker镜像中做一次发布了。大家按我下面的说明即可自行完成。

给python服务增加模块加载能力

在python服务所在的py文件【tms的docker镜像里是/home/tms/python/py.py】中增加三个东东:

1、导包语句中增加:

import importlib
from jx.mainService import mainService

2、给Py类增加一个对象函数loadNewPy:

class Py(jxGoBaseService):

    def loadNewPy(self,params):
        try:
            mn = params['moduleName']
            module = importlib.import_module(mn)
            jxGo.log('info',f'接收到命令,加载模块【{mn}】:ok')
            return {'ty':'response','cmd':'loadNewPy','rc':'ok'}
        except Exception as e:
            jxUtils.error(repr(e))
            return {'ty':'response','cmd':'loadNewPy','rc':'error'}

loadNewPy函数就是用来加载新模块的。

3、设置主服务

py = Py('pyService',hn,'demo1')
#
#在这里增加新的语句
mainService.set(py)
#
py.start()

增加主服务的动态扩展能力

1、在python目录的jx子目录下的jxGoBaseService.py文件中给jxGoBaseService类增加一个对象函数:

def addCmd(self, cmd, func):
    self._cmdSwitch[cmd] = lambda ps:func(ps)

2、在python目录的jx子目录中增加一个mainService.py文件,在其中输入:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import traceback

class mainService:
    _Service = {}
    @classmethod
    def set(cls, s):
        ms = cls.__dict__['_Service']
        ms['main'] = s

    @classmethod
    def register(cls, cmd, func):
        ms = cls.__dict__['_Service']
        ms['main'].addCmd(cmd,func)

上面三步就已经完成了给python服务增加动态升级能力的所有工作,我们下面就测试一下。

测试动态扩展能力

1、在python目录中新建一个test子目录,在命令行执行:

cd /home/tms/python
mkdir test
cd test
touch __init__.py

即将test子目录作为模块,否则放入其中的py文件无法加载。

然后启动python服务:

cd /home/tms/python
python3 py.py

2、另起一个登录会话,在test子目录中增加一个test1.py,在其中输入:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

from system.mainService import mainService

def testSAF(params):
    print(params)
    return {'ty':'response','cmd':'testSAF','data':'okkk'}

mainService.addCmd('testSAF',testSAF)

test1.py是在主服务启动后添加的,所以我们的目标就是如何通过jxTMS来执行test1.py中的testSAF函数。

下面我们在jxTMS增加相应的测试页面和代码。

3、在web文件中增加:

//testCmd
web testCmd type div;
web testCmdT1 parent testCmd type table title='testCmd',width=900,alone=true;
with testCmdT1 row 0 col c0 web n type text text="testCmd:",width=150;
with testCmdT1 row 0 col c1 web n bind testInput type input width=150;
with testCmdT1 row 1 col c0 web n type button width=150,text='testCmd',
    motion=cmd,demand=testCmd;
with testCmdT1 row 1 col c1 web n type button width=150,text='testCmd2',
    motion=cmd,demand=testCmd2;

4、在capa.py文件中增加:

@myModule.event('cmd', 'testCmd')
def testCmd(self, db, ctx):
    #加载新的模块
    ps = jxJson.getObjectNode()
    mn = self.getInputString('testInput')
    ps.set('moduleName',mn)
    #向python扩展发送命令,并送入参数ps
    rs = catalogService.call('pyService.pythonDemo.demo1','loadNewPy',ps)
    jx.log('rs:{}',rs)

@myModule.event('cmd', 'testCmd2')
def testCmd2(self, db, ctx):
    #测试新的模块中扩展的能力
    ps = jxJson.getObjectNode()
    mn = self.getInputString('testInput')
    ps.set('testSAFPPPP',mn)
    #向python扩展发送命令,并送入参数ps
    rs = catalogService.call('pyService.pythonDemo.demo1','testSAF',ps)
    jx.log('rs:{}',rs)

5、在op.py文件中增加:

@biz.Demand('disp','testCmd')
@biz.OPDescr
def op1(json):
    json.setShortcut('演示'.decode('utf-8'),'testCmd'.decode('utf-8'))

保存web、capa.py、op.py三文件,并上传,然后做一次热机刷新

然后刷新页面以重新登录。

点击快捷栏【演示->testCmd】,然后在输入框后输入:test.test1后点击【testCmd】按钮,可在python控制台看到日志输出【去除日期等信息】:

pyService.pythonDemo.demo1 从【demoHost1】接收到控制命令:loadNewPy

这代表test1.py加载成功.

点击【testCmd2】按钮,可在python控制台看到日志输出【去除日期等信息】:

pyService.pythonDemo.demo1 从【demoHost1】接收到控制命令:testSAF

同时在控制台看到print打印的jxTMS送入的参数:

{'testSAFPPPP': 'test.test1'}

与此同时,还在jxTMS的日志输出中看到testSAF命令执行后的响应:

rs:{"cmd":"testSAF","data":"okkk","ty":"response"}

这代表test1.py中的新功能testSAF得到了正确的执行。

结语

jxTMS本就具备热机刷新的动态升级能力,现在python服务也具备了动态升级能力,jxTMS就拥有了完整的动态升级能力。

这将有助于充分发挥jxTMS在业务管理方面强大的低成本定制能力,再结合python的生态,实现了强大的、稳定的全能力业务支持与定制。

注1:上面的演示其实还缺了一个重要的能力:如果python服务重启了,通过loadNewPy动态扩展的模块是无法自动加载的。解决办法是利用python的pickle实现本地存储

注2:目前的迭代中,loadNewPy已经移入了jxGoBaseService,并用本地存储弥补了上面的缺失,过些天会和其它升级一起打包到新版本的docker镜像中发布

参考资料:

jxTMS设计思想

jxTMS编程手册

下面的系列文章讲述了如何用jxTMS开发一个实用的业务功能:

如何用jxTMS开发一个功能

下面的系列文章讲述了jxTMS的一些基本开发能力:

jxTMS的HelloWorld

你可能感兴趣的:(jxTMS,python,docker,jxTMS)