影子模块与灰度转正
影子 = 同一模块的新版本,以独立 owner(如 roll_shadow)与线上旧版
并存试运行:它收到真实事件的副本、其出站被拦截记账而非真正发出——
在 shadow_diff 里对比两个版本的行为,确认无害后 promote 一键转正,
dismiss 随时放弃。模块代码零改动,全程运行时 API 驱动:与
load / unload / reload 同类的运维动作,Dashboard / 自定义管理模块直接
调用,没有任何配置项要写。
{!--< tips >!--}
- 启动:
await sdk.module.shadow_start("roll", source="路径/到/v2")——新版代码以独立 owner(默认取路径名)与旧版并存 - 影子不参与真实分发与依赖图:同名命令进影子目录、路由只登记不挂载、
生命周期广播静默、
module.call与依赖解析仍指向 v1 - 转正永远由人确认:
await sdk.module.promote_shadow("roll"),失败 自动回滚旧实例继续服务;dismiss_shadow随时放弃 {!--< /tips >!--}
快速上手
# v2 代码:普通模块写法,零影子感知(任意目录,如 downloads/roll_v2/)
# 线上机器人里(Dashboard / 管理模块调用),一行启动灰度:
await sdk.module.shadow_start("roll", source="downloads/roll_v2")
# → 影子以独立 owner "roll_v2" 与 v1 并存,出站被拦截记账
# 试运行期间对比行为:
report = sdk.module.shadow_diff("roll")
# {"shadow_owner": "roll_v2", "count": 3, "aligned": [...]}
- v1 实际发送:来自收件箱(transcript)的 bot 时间线
- v2 意向发送:影子账本(出站闸记录的"想发什么")
- 两者按
trace_id对齐——同一条消息,两个版本各自为什么触发/没触发、 想发什么/实际发了什么,一目了然
确认无误后转正:
await sdk.module.promote_shadow("roll") # 转正,失败自动回滚 v1
await sdk.module.dismiss_shadow("roll") # 或:放弃影子
五道隔离闸
| 闸 | 机制 |
|---|---|
| 事件副本 | 影子处理器收到事件的独立副本(带 shadow 标记)——影子的改写 / 认领 / 停止传播只作用于副本,不影响原事件链 |
| 出站闸门 | 影子的 Send DSL 与 Api 调用全部拦截记账(成功形状假响应),不真正发出——影子不会重复回复 |
| 存储覆盖层 | 影子的 KV 写进入内存覆盖层并丢弃落库;读先查覆盖层、未命中透传真库(灰度对着真实数据跑);删除记墓碑 |
| 路由屏蔽 | 影子的 HTTP/WS/SSE 路由只登记不挂载;同名命令进影子命令目录、平台事件方法注入禁止 |
| 生命周期静默 | 影子不广播自身的生命周期事件、不参与生态依赖图(module.call 与依赖解析仍指向 v1,避免半成品被依赖) |
配置继承:影子默认继承原模块的配置节(否则灰度失真),转正后配置原地生效。
诚实边界(拦不住的)
- 走框架的发送 / API / KV 存储 / 统一 HTTP 客户端全部拦得住;
模块绕过框架裸起
aiohttp、开线程写外部系统——框架拦不住 - ORM 读写不在覆盖层语义内(按行 overlay 无法在 SQL 层干净实现)—— 影子期间建议避免依赖 ORM 写隔离
- 影子源为本地路径:新版代码以路径导入、独立 owner 装载;同一 PyPI 包
在同解释器内受
sys.modules单键限制,无法新旧两版本并存 - 泄漏审计器(
sdk.module.audit)可见影子资源归属;绕过框架的副作用 至少不会无声
转正与回滚
promote 流程:快照当前版本(含级联依赖者)→ 完全卸载 → 影子以真名注册
加载 → 任一步失败自动回滚、旧实例继续服务(尽力而为语义:on_unload 已
执行的副作用不可撤销,回滚后旧实例处于已收尾态)。转正成功的影子资源被
回收、绑定解除;原模块配置节原地生效。
持久化提醒:promote 是运行时切换——重启后仍以 v2 运行,需要把新版本
持久化安装(pip install -U 新版本 / 替换插件文件)。运行时切换不会
替你完成包管理。
相关文档
- 归属权(owner)系统——影子以独立 owner 隔离的机制基础
- 交互会话——
trace_id与收件箱(diff 对齐的数据源) - 作用域(scope)——事件准入与出站控制面