U38 Seata SAGA 状态机实验
2026-10-30 在本机 MySQL 8.4.7、Seata 2.5.0、JDK 21 和 Spring 5.3.31 的隔离环境完成两项测试,退出码 0;依赖树、观察标记和清理结果见运行证据。以下结论仅覆盖本次输入和运行环境。
实验针对固定 Seata 2.5.0 状态机 API:正常路径在独有 MySQL 库中写入合成订单并验证持久 CHARGED;失败路径先写入 RESERVED,故意让后续调用和补偿失败,观察仍需处理的业务状态;然后显式调用 StateMachineEngine.compensate(instanceId, replacementParams) 重试,观察状态变为 RELEASED,并从状态日志存储重新读取补偿状态。示例参考固定版本上游补偿恢复测试与状态定义,业务状态、参数和断言为本实验设计。
实现时先后发现两类示例问题:startWithBusinessKey 会修改传入参数表,不能传不可变 Map.of;服务结果使用不可变 map 时,Jackson 序列化后的类型信息不足以供状态日志重新读取。本例使用可修改的 HashMap 并保持 jackson 解析器,最终重新运行通过;这不证明所有参数类型都可序列化。
合成业务以订单键作为稳定身份:处于 RESERVED 的相同预留可重复,RELEASED 的相同释放可重复,重复扣款仅在已 CHARGED 时接受;释放后重新预留或扣款视为冲突。测试包含重复操作和冲突反例;这是此最小示例的身份规则,不覆盖含金额、数量等参数的业务一致性校验。
实验资源:运行入口、POM、测试、隔离环境、业务服务、预期异常、状态机、Spring 配置、客户端配置、注册配置、SAGA 建表、TC 建表。
启动前
- 需要 JDK 21、Maven 3.9、DBngin 本机 MySQL 8.4.7(实验当前仅支持本机
root空密码)、本地已有的 Apache Seata 2.5.0 发行包和 MySQL Connector/J 9.7.0。 - Maven 坚持离线运行;需预先准备项目与测试依赖以及
maven-dependency-plugin,入口会检查离线依赖树中的 Seata 模块版本。任何缺失工件和传递依赖必须在下载前向本机用户说明来源、用途、磁盘与内存占用并取得同意;下载使用独立临时缓存,用完删除。 - 需要启动本实验独占的 TC:固定 Seata 2.5.0、JVM 堆 64–128 MiB、最多 2 个可用处理器;Maven 堆上限 256 MiB、测试 JVM 堆上限 192 MiB,实际进程内存还包括堆外。磁盘需临时容纳 TC 日志、两个测试数据库及授权下载的工件;实际用量待测。实验结束关闭 TC,不能修改本机已有服务。
- 原版 Seata 2.5.0 的 RPC 监听所有接口;本实验复用 U38 的 loopback agent 将监听地址调整为
127.0.0.1并校验 PID 实际监听,事务代码不改。若 18091 已占用,立即失败,不能连接或停止已有服务。
经用户明确许可启动后,从仓库根目录执行:
python3 labs/seata-saga/run.py --allow-start-tcrunner 先离线编译和检查依赖树,再启动测试;成功时记录两个测试、三个观察标记、版本与结果。启动失败、中断和测试失败都不能记为通过。输入、退出状态和观察以生成的 evidence/u38-saga.json 为准。
隔离和清理
程序为每次测试生成随机 128 位身份,创建 study_u38_sagatc_<id> 与 study_u38_sagabiz_<id> 两个独有数据库,以及独占临时目录。创建前写入所有权文件,建库后在库内写入随机令牌。
Java 测试正常结束或执行 shutdown hook 时,先关闭自己启动的 TC,再依据本次创建标志和随机库名检查库内令牌;令牌一致才删除该库。此路径不读取所有权文件。Python runner 的兜底清理则逐项核对所有权文件名、文件内令牌和库内令牌,确认匹配后才删除仍存在的库,并检查端口空闲;最后删除自己的临时目录。缺少库内令牌、权限错误或所有权不明确时保留资源并报告,不以通配符清理。runner 被 SIGKILL 或机器中断可能来不及清理,需据其独占目录的 ownership 文件和库内 u38_saga_owner 人工核查,确认一致后再定向处理。绝不删除已有数据库或依赖缓存。
验证边界
sagaBranchRegisterEnable=false不取消 TC 依赖,也不证明向 TC 注册了 SAGA 分支;实验中的compensate是应用显式触发。- 状态日志
reload和补偿重试发生在同一测试 JVM;不能声称新进程恢复、TC 自动恢复、跨机器或断电恢复已验证。 - 业务示例只证明独有数据库内的合成资源状态,不能由状态
SU推导外部支付、发货等系统的真实一致性。永久补偿失败需要业务处置。 - 本次 Seata 发行包、loopback agent 构建脚本与驱动使用本机已有文件;Maven 依赖按用户许可从 Maven Central 准备到独立临时缓存,实验后清理。实验临时启动单机 TC,完成后关闭。