需要实现的效果,比如一个服务在跑,然后服务依赖 n 个插件,插件放在单独一个文件夹里,每一个文件对应一个插件,插件随时可以变化,主体服务希望能不重启直接动态载入新代码这样
印象里多年前研究过这个功能,是可以实现的,但是好像有些麻烦。有什么现成的轮子吗?
1
noqwerty 2023-03-11 17:04:39 +08:00
可以直接用 importlib 实现: https://docs.python.org/3/library/importlib.html
|
2
learningman 2023-03-11 21:10:10 +08:00
加载用 importlib 是可以搞的,但是清除旧的非常麻烦
|
3
ClericPy 2023-03-11 21:10:25 +08:00
我刚做了一个类似的...
假装是个动态脚本的 RPC, 通过 URL route 选择模块路径, 比如类似格式和很多常见模块的 entrypoint 一样, package.module:function 的方式, 传参兼容 params 和 Post form 以及 post JSON 多种方式, 目前参数只支持 kwargs 直接塞函数 **kwargs 里, 之后会根据 inspect 提取函数参数列表来做 validate 相关以及自动生成表单 然后动态载入刷新代码什么的, 我是每隔一段时间或者用 watchfile 的方式查看文件变化就从 sys.modules 里删掉, 下次导入就是新的代码了, 以前想过太多 reload 的用法, 发现最简单的就是直接删掉旧的... 这套东西还没时间开源, 难度不大自己琢磨琢磨也就明白了 |
4
LeeReamond OP @ClericPy 你的意思是用 insepect 监控代码有没有变化,有就删掉旧的,然后每个插件用某种特定方式命名这种感觉?
|
5
ClericPy 2023-03-11 22:01:25 +08:00 1
@LeeReamond
什么啊... inspect 查看函数入参类型的, pydantic 做校验, 类型错误就不执行了 监控变化用 watchdog 看文件变化, 删掉的逻辑是你只要导入过的模块一般 sys.modules 里面 del 掉, 再导入一次就是新代码了, 不用特定命名, 只要 import path 固定一个目录, 会自动去搜模块名字的. 我那个格式是 URL 路径的格式, 不是命名格式 如果不放心害怕有篡改文件或者有人偷偷注入什么东西, 我之前还想了做对整个 .py 文件加盐哈希然后哈希值放到文件第一行, 到时候导入前先判断文件对不对 |
6
lolizeppelin 2023-03-12 11:50:58 +08:00
|
7
lolizeppelin 2023-03-12 11:51:42 +08:00
哦 看错了不好意思...
|
8
featureoverload 2023-03-13 14:21:56 +08:00
不是有特殊需求的软件,就实现 os.fork+importlib.import_module 好了。这种应该是最简单的
|
9
featureoverload 2023-03-13 14:24:55 +08:00
@featureoverload 这种应该是最简单的机制了。
有内存数据(变量 /对象 /数据结构)交换的话,就使用 multiprocessing+importlib.import_module 可以解决。 |
10
LeeReamond OP @featureoverload fork 在这里是干什么用的呢
|
11
featureoverload 2023-03-14 09:51:51 +08:00
@LeeReamond 原本的程序(父进程)负责主 /核心逻辑,比如判断动态导入等。
在需要动态导入的时候,以及动态导入之后(使用导入的模块)做的事情,在 fork 出来的程序处理。 这样 [动态导入做的事情] 完成之后,fork 出来的程序(子进程)就让它自己结束--进程销毁; ------ 这样就是“业务逻辑”和“核心逻辑”分离,包括进程内的一切变量等等。 核心逻辑控制什么时候动态导入,业务逻辑实际执行导入和业务行为。 |