7.6 KiB
P3 计划调度阶段记录
验证日期:2026-09-17。已交付计划管理与持久化调度闭环,P3 仍有运行中取消、配额/背压、可靠订阅待完成;本报告不替代全平台生产验收。
1. 已实现行为
- 五段 Cron 与 fixed-rate;显式时区、开始和结束边界,固定间隔保持基准,不按任务完成时间漂移。
- 时区快照随定义冻结,服务从内置数据加载,不依赖宿主机或 ZONEINFO;兼容已有快照是后续升级约束。
- 创建、队列分页、详情、完整版本发布、历史版本、暂停/恢复、触发历史。每个命令有当前权限校验、幂等回执与管理审计。
- SKIP / COALESCE / CATCH_UP 漏跑策略与 PARALLEL / SERIAL / SKIP 重叠策略;明确补偿窗口、延迟容差、批量和扫描间隔。
- 发布新版本保留旧生效边界前的积压;跳过和合并范围不越过版本边界。已产生任务保留当时模板。
- 多节点用数据库锁与唯一触发身份竞争;触发决定、对应任务、事件及进度一起提交。
- 实际 orbit 命令持续扫描,独立 SDK 与 完整周期快照示例 同步交付。
- 迁移 000006 增加运行字段与索引,实体仍为 32 个;新模型字段及 SQL COMMENT 均为中文;源码核对 32 个持久化模型、253 个直接声明的持久化字段均有中文说明。
完整字段、权限、状态与示例见 接口手册。
2. 环境、命令及结果
macOS 本机,Go 1.27.1,Docker 单实例 MySQL 8.4.10。临时随机凭据、回环随机端口,运行结束清理容器;不使用业务数据库。
make fmt
make test vet build
make integration
cd sdk/go
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
上述检查均已通过。未配置集成环境时,普通 go test 会跳过真实数据库/进程用例;实际证据来自 make integration。
最终完整集成输出:
| 测试组 | 本次结果 |
|---|---|
| MySQL 全部集成 | PASS,44.712 秒 |
| 计划事务与管理子集 | PASS,31.62 秒 |
| SDK Worker 连接/运行器及安全重试 | PASS,62.912 秒 |
| SDK 计划生命周期 | PASS,4.43 秒,含包启动/竞态开销 5.675 秒 |
| 真实进程故障组 | PASS,21.487 秒 |
| 新增调度进程强杀恢复 | PASS,10.23 秒 |
| 七个可运行示例 | health / tasks / worker-protocol / worker / history / retry / schedules 全部通过 |
时间为一次测试运行耗时,不能用作吞吐、延迟或容量指标。
3. 时钟与规则证据
规则测试 验证:五段/分钟边界、亚洲时区、纽约缺失/重复小时、Lord Howe 半小时夏令时变更、Apia 整天跳过、2096→2104 世纪闰日、月日/星期 OR、固定间隔微秒和跨 292 年计算、结束排除边界、规则副本隔离及无解日期拒绝。
时区测试 核对内置快照完整 SHA-256、禁用外部 ZONEINFO 后仍能加载、精确名称及缓存,以及未知快照拒绝。快照来自 Go 1.27.1,附 Go 许可。Cron 库版本固定为 v3.0.1,只用于解析和 UTC 日历计算,运行不依赖外部调度服务;SDK 未新增该依赖。
有限决策测试 覆盖补偿窗口截断、跳过、合并、有限逐点补跑、串行阻塞、重叠跳过、未来点不处理,以及合并不越过版本生效边界。计算器不自行读取系统当前时间,执行使用资源锁定后的数据库时间。
4. 实际数据库与 SDK 证据
- 两个不同节点身份并发扫描同一到期计划,只创建本批三个唯一任务;再次扫描不能绕过持久化冷却时间。
- 禁用命名空间后,即使计划已到期也不再产生任务。
- 创建原键重报、同键不同内容冲突、暂停禁止触发、恢复原回执、跨命名空间/队列范围拒绝。
- 暂停期间发布新模板,旧积压仍用旧版本;历史版本不可被新模板覆盖,旧点处理后游标推进到新版本。
- 连续发布三个有限版本:第二版本尚待初始化时再次发布,仍保存其积压;空历史版本之后的末版全部处理完时,不重新扫描已完成触发点。新增用例先复现了漏掉中间版本和重复写入冲突,再验证修复。
- 超过时间窗口的跳过范围、漏跑合并范围与任务关联实际落库,范围结束边界大于起点。
- SERIAL 在待执行任务存在时等待;明确取消前项后继续;前项进入 UNKNOWN / NEEDS_REVIEW 后再次停止推进。
- 通过测试触发器让 occurrence 写入失败,任务、触发记录及游标整体回滚;故障解除后正常提交。
- 触发游标分页无重复,不能跨计划复用游标;任务模板中的大整数文本保留。
上述用例以真实时间等待形成积压,不把原触发时间改到计划创建前。少量用例将受控行 check_at 设为当前时间,以加速核对连续历史版本或阻塞状态;冷却限制另有未改写 check_at 的竞争测试。
SDK 用例 连接实际服务,通过独立 SDK 创建暂停计划、幂等核对、恢复、自动 Worker 成功、暂停、发布 Cron 新版本、读取两个版本、原发布回执重报、列表及暂停期间不新增触发。业务结果中的 9007199254740993 保持精确。
5. 实际进程强杀恢复
新增 TestIntegrationWorkerProcessScheduleRecovery 使用构建后的 orbit 可执行文件和临时 MySQL:
- 节点 A 创建一个每秒触发、共八个原触发点的有限计划,CATCH_UP / PARALLEL,每批上限二。
- 观察到首个触发已经落库后,向 A 发送真实强杀并 Wait 确认退出。
- 保留三秒无 Orbit 服务的间隙形成漏跑,不修改数据库时钟或计划游标。
- 启动身份不同的 B、C 两个真实服务进程,从持久化进度竞争接续。
- 查询至计划结束,严格核对恰好八条 FIRED、八个不同 TaskID、原 scheduled_at 序列及相同版本;每条都有完整 WAITING 任务与原模板。
这证明了本地单 MySQL 下服务进程消失后的持久化接续与多进程触发去重。本用例不启动业务 Worker,不宣称验证外部副作用 exactly-once。原开始/完成 ACK 丢失后强杀接管、Worker 进程中断转核查等 P2 用例也同步通过。
6. 可运行场景与当前边界
周期快照示例输出两条不同的 occurrence/task 身份,均完成 SUCCEEDED,随后 paused=true completed_tasks=2 current_version=1、worker_drained=true running=0。示例不访问外部业务资源;计划有十秒结束边界,正常完成后暂停,历史保留。
仍需后续验证或开发:
- 运行中任务取消、细粒度限流与队列配额、可靠结果订阅;流程引擎及人工核查控制。
- 调度期间数据库故障切换、提交 ACK 丢失的专门故障矩阵、跨主机网络分区、备份恢复和混合版本升级。
- 大表在线 DDL、历史人工计划行核查;000006 不自动启用旧的未绑定队列行。新建数据库与既有 v4 数据升级到当前结构的通用测试通过,但这不是旧人工计划内容的完整迁移验收。
- 大规模公平性、行锁竞争、重试/补跑风暴、历史保留与清理、租户配额。当前批量、扫描间隔和参数复制限制只建立有界基线,没有百万租户容量结论。
后续继续 持续计划,不将本阶段闭环标为整个 P3 或最终目标完成。