Files
orbit/docs/reports/phase-3-batch-tasks.md

96 lines
6.9 KiB
Markdown
Raw Permalink 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及部分补交场景;不代表P3或全平台验收完成。完整集成已通过,下面记录实际覆盖范围与剩余边界。
## 1. 实现与证据入口
- [服务契约](../../pulse/service/batch.go):最多32项,逐项独立事务与幂等,ACCEPTED/REJECTED/UNKNOWN/NOT_ATTEMPTED四类结果。未知数据库结果或凭据失效后停止余项,上下文结束保留已确认前项。
- [HTTP入口](../../internal/transport/httpserver/tasks.go):`POST /v1/tasks:batch`,全体正文严格解析后才受理,每项正文幂等键,总请求512 KiB。完整响应使用HTTP200,逐项标记结果。
- [独立SDK](../../sdk/go/batch.go):SubmitTasks及中文字段说明,不自动生成身份、拆批或重试;校验返回数量、顺序、状态与回执归属。
- [运行示例](../../examples/batch/main.go):两项受理、一项满额,原键核对后释放配额,仅补交被拒项并取消收尾。
- [接口手册](../api/batch-tasks.md)、[场景说明](../examples/batch.md)、[开发计划](../08-development-plan.md) 同步维护。
不增加数据库模型或迁移,平台仍为35个实体、289个中文注释持久化字段;不增加外键、级联或SDK数据库依赖。
## 2. 验证环境与命令
macOS、Go1.27.1、Docker单实例MySQL8.4.10。使用一次性数据库、随机测试凭据及回环端口,结束后自动删除,不修改已有业务库。
```sh
make fmt test vet build
make integration
```
普通测试没有数据库环境时会跳过Integration;数据库/HTTP/进程证据来自真实集成入口。并发修复另在一次性数据库重复执行:
```sh
go test -race -count=20 \
-run '^TestIntegrationTaskBatch/concurrent_replay_and_shared_application_backpressure$' \
-v ./internal/storage/mysql
```
该定向命令要求 `ORBIT_TEST_MYSQL_DSN` 指向一次性数据库;正式完整脚本会自动准备隔离环境。
| 验证组 | 实际结果 |
| --- | --- |
| fmt / race / vet / build | 已通过 |
| 定向批量MySQL六组场景 | PASS,5.559秒,含包开销 |
| 真实HTTP丢失批量响应及SDK补交 | PASS,1.458秒,含包开销 |
| 完整批量示例 | 已通过,unfinished=0 |
| 同键并发与共享配额20次重复 | PASS,10.110秒;每轮8个调用者 |
| 全量MySQL集成 | PASS,94.874秒 |
| SDK Worker完整组 | PASS,88.099秒 |
| SDK调度 / 队列资源 / 批量受理 | PASS,5.640 / 4.474 / 1.361秒 |
| SDK订阅管理 / 事件消费 | PASS,33.508 / 51.852秒 |
| Inbox六组真实数据库/消费者故障 | PASS,35.783秒 |
| SDK应用配额 | PASS,1.426秒 |
| 九项节点/Worker进程故障 | PASS,69.057秒;连同Inbox消费者共十项真实进程故障 |
| 全部运行示例 | 15个核心SDK示例 + 1个独立Inbox示例通过 |
上述完整脚本正常退出,状态码0;没有以尚在运行的日志推断完成。文档链接与JSON代码块核对通过,核心SDK依赖检查未包含服务端模型或MySQL驱动。以上是单次回归耗时,不是吞吐或性能指标。
## 3. 事务、权限与配额
[数据库回归](../../internal/storage/mysql/task_batch_integration_test.go) 实际验证:
1. 有效/参数无效/不存在队列/队列满额混合批次,每项结果独立;数据库仅有两份任务、受理幂等、事件及审计。
2. 单项与批量共用原始回执;取消后重报仍返回原受理版本,满额也不阻止已提交身份核对。释放配额后原失败身份受理成功,同键不同内容仍冲突。
3. 跨命名空间队列与队列权限拒绝;即使已有回执也不能绕过当前队列范围。
4. 第一项提交后撤销凭据,第二项重新认证拒绝,第三项未尝试;只有第一项任务存在。
5. 第一项提交后取消请求上下文,后缀未写入;恢复后整批原键重报,首项去重、后缀受理。
6. 真实审计触发器故障使新项事务回滚,任务/幂等/事件/配额不残留;既有已受理项保留。接口保守返回UNKNOWN,修复故障后原身份补交成功。
7. 八个调用者同时重报四个相同身份,应用上限3;前三个稳定任务ID、仅三次新受理,第四项APPLICATION_FULL,另一命名空间也受共享额度限制。
单元及HTTP边界还覆盖整批非法键/重复键/超量、全项参数无效时仍认证、未知字段/大小写别名/重复JSON键/null、超大正文、禁止整批幂等头、精确整数、不完整或矛盾的SDK回执,以及上下文和内部错误不泄露细节。
## 4. 并发回归发现与修复
最初同键并发满额场景实际出现MySQL 1213死锁,API按既有保守规则报告UNKNOWN。测试没有将UNKNOWN改判成功,也没有通过放宽断言隐藏问题。
任务提交原来先抢占幂等唯一键,再等待应用额度锁。在满额回滚和同键INSERT竞争中触发锁冲突。本轮调整为:认证 → 应用额度锁 → 提交幂等身份 → 队列 → 任务/事件/审计。取得应用锁时不检查或扣减额度;读取已有回执仍在配额检查之前。
提取只在应用锁已持有时使用的队列锁辅助函数,避免重复查询应用锁。每项事务结束后释放全部锁,整个批次不持有跨项锁。没有新增外部锁服务、数据库外键或盲目重放事务。当前场景通过不表示全部MySQL负载不再可能死锁;其他未知数据库错误仍必须原身份核对。
## 5. 真实HTTP故障与示例
[SDK集成](../../sdk/go/batch_integration_test.go) 启动真实HTTP代理:先读完平台已经生成的受理响应,再强制关闭客户端连接、丢弃响应。SDK返回网络错误,未自动补发。再次用原键/原参数请求,两项返回同一任务且deduplicated=true,第三项保持QUEUE_FULL;查询仅存在两行任务。取消一项后只补交原第三项,受理成功。
完整示例输出:
```text
accepted=2 rejected=1 code=QUEUE_FULL
replayed=2 same_task_ids=true
retried_items=1 same_identity=true accepted=true
queue=<实际ID> paused=true unfinished=0
```
这验证受理与HTTP回执恢复,不等同于Worker业务效果恰好一次,也不是业务事务Outbox。任务、队列和审计保留,无硬删除。
## 6. 兼容与尚未验收范围
- 无数据库迁移变更;批量与单项受理的身份、策略、事件和审计相同。新SDK调用旧节点返回404,不静默降级。
- 单项与批量均使用调整后的锁顺序。部署应统一升级写入节点;未做新旧二进制混合压力或滚动发布验收。
- 批次逐项串行,8秒HTTP预算不保证每次32项全部尝试;大参数回执不重复携带原输入。调用方必须处理部分提交和响应全丢。
- 本轮为本机单MySQL正确性验证,未验证数据库故障切换、跨区域网络、百万租户容量或生产RPO/RTO。
- P3仍缺独立任务人工核查/重试、业务键及时间筛选、事务Outbox示例;P4–P7仍按原目标推进。