Files
orbit/docs/reports/phase-3-task-recovery.md

86 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P3 人工核查、关联重试与操作审计回归
验证日期:2026-09-17。服务端、SDK、接口及示例已实现,完整回归已通过,脚本终态退出码0。P3剩余查询筛选与事务Outbox接入继续推进。
## 1. 实现范围
- [服务契约](../../pulse/service/recovery.go):显式历史执行结束/安全重试声明、原因、证据、版本及预算校验。
- [数据库事务](../../internal/storage/mysql/task_recovery.go):NEEDS_REVIEW核查为SUCCEEDED/FAILED,原尝试保留;独立FAILED/CANCELLED任务生成retry_of关联后继,原任务不改写。
- [审计查询](../../internal/storage/mysql/task_operations.go):专门权限与父资源范围,摘要游标分页、详情原因和证据,真实凭据身份。
- [Go SDK](../../sdk/go/recovery.go)、[接口手册](../api/task-recovery.md)、[完整运行场景](../examples/recovery.md)及[源码](../../sdk/go/examples/recovery/main.go)。
- [迁移000015](../../internal/storage/mysql/migrations/000015_task_manual_recovery.up.sql):现有RetryOf字段中文语义、同父后继唯一索引与禁止自身关联CHECK。35个模型、289个持久化字段,无新增字段,无外键/级联。
## 2. 已覆盖的数据库与协议场景
[真实MySQL测试](../../internal/storage/mysql/task_recovery_integration_test.go)包含八组场景:
1. 核查保存新权威结果、保留旧尝试,释放一次额度;同键重报原audit_id,旧needs_review快照不改写,新终态单独交付,迟到成功只记录证据。
2. 普通凭据不能核查或读取管理审计;显式授权后可用。跨命名空间/错误父任务拒绝,游标绑定任务/种类;撤销队列范围后原回执也不能绕过权限。
3. 审计INSERT触发器故障整体回滚核查、额度、幂等及新结果事件;两个不同键竞争同一版本仅一个成功。
4. 未核查任务不能重试,队列满额不残留身份/子任务;释放后原键成功,新任务新预算、原载荷/冻结策略,原任务不变;迟到报告不覆盖核查。
5. 人工重试审计故障回滚新任务及额度;八个不同键竞争同一父任务仅一个直接后继和一条task.retry审计。
6. 真实串行计划因未知结果停止推进;合法归属核查后可推进下一触发,但计划任务不允许独立人工重试。
7. 等待、运行、成功、带门控或无效计划关联的恢复均拒绝,不能借无外键设计绕过所有权。
8. 流程所属任务拒绝直接核查,归属恢复后普通任务可核查;计划任务拒绝独立派生。
[HTTP输入边界](../../internal/transport/httpserver/recovery_test.go)与[服务参数边界](../../pulse/service/recovery_test.go)覆盖缺失/null/false声明、未知actor_id/owner_id、重复JSON键、非规范revision、证据空白/长度、结论/结果/预算限制。
[SDK测试](../../sdk/go/recovery_test.go)核验原幂等头、字符串版本精度、审计游标编码、非法路径拒绝、矛盾核查回执及缺少重试来源时拒绝确认成功。
## 3. 无外键与迁移回归
真实v7→当前:70个历史外键全部删除,旧任务数据不变;323个未替换索引组件保留,单独核验(namespace_id,retry_of)新唯一索引。新装库外键为0。一次性库注入违规外键后启动结构检查拒绝就绪,移除后恢复。
本轮初次升级测试发现MySQL在新增同列唯一索引时会撤去原隐式非唯一索引fk_pulse_tasks_3。新迁移明确用唯一索引替换该冗余索引,测试分别核验替换对象和其他索引,避免将有意替换误报为数据损坏;没有增加数据库外键。
全量回归还发现旧v9升级夹具没有撤除新迁移15的约束,导致重放时重复CHECK名称;已修正一次性库夹具的还原步骤,保留真实生产迁移内容和校验和规则。
## 4. 环境与复现
macOS、Go1.27.1、Docker单实例MySQL8.4.10,隔离临时数据库与回环端口,结束自动清理。
```sh
make fmt test vet build
make integration
```
完整脚本为人工恢复单独初始化--worker-access与--recovery-access凭据,普通Worker测试凭据不扩权。集成SDK通过[真实HTTP代理](../../sdk/go/recovery_integration_test.go)在核查和重试提交后丢弃响应,再原身份核对;并在真实WSS派发中验证retry_of。
| 验证组 | 本轮已取得的结果 |
| --- | --- |
| fmt / race / vet / build | PASS |
| 人工恢复八组数据库用例 | PASS,5.32秒 |
| v7无外键升级 / 全量MySQL集成 | PASS,4.85 / 104.575秒 |
| SDK Worker完整组 | PASS,87.918秒 |
| SDK计划 / 队列 / 批量 | PASS,5.659 / 4.536 / 1.366秒 |
| SDK订阅管理 / 事件消费 | PASS,33.379 / 51.798秒 |
| 新人工恢复SDK及两次HTTP丢回执 | PASS,3.371秒(含包开销) |
| Inbox六组真实数据库与消费者故障 | PASS,35.606秒 |
| SDK应用配额 | PASS,1.357秒 |
| 九项节点/Worker进程故障 | PASS,60.644秒;连同Inbox消费者为十项真实进程故障 |
| 全部运行示例及脚本终态 | 16个核心SDK示例 + 1个独立Inbox示例通过,完整脚本正常退出0 |
新人工恢复完整示例已通过;核心SDK依赖图未包含服务端包或MySQL驱动,文档575个本地链接、45个JSON块检查通过。最终结果取自已经结束的进程,未将中途日志当作全量通过。单次耗时仅为回归记录,不作为性能指标。
## 5. 实际HTTP响应丢失与运行结果
SDK集成代理先完整收到服务端成功响应,再主动关闭客户端连接。核查和人工重试各丢一次响应;测试关闭HTTP连接复用,确保不会因传输层隐式重发掩盖首次网络错误。原键重报后分别恢复同一audit_id和同一子任务,审计分页确认仅一次task.review和一次task.retry。
WSS接收的新任务带有正确retry_of,执行成功后原任务仍FAILED。旧Worker再报成功时返回EVIDENCE_ONLY,原任务版本/结果不变;原执行尝试也未被核查改写。
完整示例实际输出模式:
```text
source=<原任务ID> state=FAILED retry=<新任务ID> state=SUCCEEDED audit=<审计ID> operations=4
```
本例四条审计对应受理、原结果、核查与人工重试,开始事件本身不额外增加一条管理审计。没有自动删除历史。
## 6. 生产边界
- 人工执行结束与安全重试是获授权主体基于外部证据的声明;平台不会自动证明外部物理停止或恰好一次。旧迟到报告保留证据,不重新打开已核查终态。
- 计划生成任务可核查但不能独立人工重试;流程所属任务/门控恢复留Weave控制器,不声称本阶段已实现流程恢复。
- 独立新任务仍受原应用/队列配额、冻结自动重试策略和执行权限约束;业务幂等身份必须沿原操作保持,不能用新taskID盲目调用外部接口。
- 任务详情和派发新增可选retry_of;旧SDK忽略未知响应字段,旧严格Schema需更新。迁移前停旧写入节点,不回改历史迁移,不自动清理非法历史关联。
- 本机正确性/进程故障不等于生产多故障域高可用、MySQL切换或百万租户容量验收;P4–P7仍按持续目标推进。