Files
orbit/docs/reports/phase-3-queue-resources.md

76 lines
7.0 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。本阶段完成队列配置、并发降额、开始限速及未终结任务背压。P3 仍需应用级配额、业务键许可、优先级/公平性和可靠订阅;持续目标保持进行中。
## 1. 已实现范围
- `POST /v1/queues/{id}:configure` 完整替换暂停、并发、开始速率和未终结任务上限,带授权、CAS、稳定身份、事件和管理审计。
- 基于数据库时间的一秒开始计数窗口,多节点共享;Start 事务消费额度,旧回执重报不重复计数,节点更换不清零。
- 领取预留尚未开始的窗口空间,满额时保持 WAITING。领取后降额可使 Start 返回 RATE_LIMITED,自动 SDK 保留原消息身份退避核对。
- 未终结任务额度涵盖等待、预占、运行和核查;首次受理增加、首次终态减少,重试和迟到证据不重复变更。
- 满额受理返回 HTTP 429 / QUEUE_FULL / Retry-After: 1;原已受理请求仍可补取回执。SDK 提供类型化错误及 RetryAfter,不自动重报写请求。
- 计划补跑受相同积压上限限制,保留未受理的原触发点;释放空间后按冻结漏跑策略接续。
- 迁移 000009 增加四个队列字段并回填既有未终结任务,Go/SQL 均有中文说明,无数据库外键。
- 源码核对 257 个直接声明的持久化字段均有中文注释;实体仍为 32 个。
- [队列接口与完整 SDK 场景](../api/queues.md)、[resources 示例](../../sdk/go/examples/resources/main.go) 同步交付。
## 2. 环境及执行结果
macOS、Go 1.27.1、Docker 单实例 MySQL 8.4.10。使用独立临时数据库、随机凭据及回环端口,结束后清理测试容器,未使用业务数据库。
```sh
make fmt test vet build
make integration
cd sdk/go
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
```
全部通过。完整集成后补充了并发开始竞争、Start 回滚、配置作用域及旧库额度回填断言,对 QueueResources 与 SafeRetryUpgrade 重新运行真实 MySQL 竞态回归并通过;修改的测试包再次通过 vet。没有用跳过数据库的普通单元结果代替真实集成证据。
| 测试组 | 实际结果 |
| --- | --- |
| 完整 MySQL 集成 | PASS,64.830 秒 |
| SDK Worker 全部连接/运行器回归 | PASS,80.819 秒 |
| SDK 计划生命周期 | PASS,含包开销 4.579 秒 |
| 新增 SDK 资源生命周期 | PASS,3.19 秒,含包开销 4.414 秒 |
| 真实服务/Worker 进程故障组 | PASS,21.425 秒,包含新增积压额度强杀恢复 |
| 补充资源与升级检查 | PASS,16.228 秒;资源用例 11.00 秒,升级用例 3.85 秒 |
| 九个完整示例 | health / tasks / worker-protocol / worker / history / retry / schedules / cancellation / resources 全部通过 |
上述为测试用时,不是吞吐或延迟指标。
## 3. 数据库及竞争证据
[资源集成用例](../../internal/storage/mysql/queue_resources_integration_test.go) 验证:
- 积压上限为 3 时,16 个并发提交恰好 3 个受理,其余为 QUEUE_FULL;拒绝请求不残留幂等占位,已受理原身份在满额下仍可查询回执。取消后可再次受理。
- 两个节点、两个独立 Worker 实例先各领取任务,随后将开始上限从 4 降到 2,四个并发 Start 恰好两个通过,其余限流;任务/许可保留。
- 强制 Start 事件写入失败后,任务仍为 LEASED,开始计数为零,原消息可在故障解除后重试。
- 跨命名空间及队列范围受限的配置修改被拒,拒绝操作不残留配置身份。
- 暂停禁止领取和 Start,但仍可提交与取消;配置同身份返回原快照,旧版本新操作冲突,成功变更各有一条审计。
- rate=1 时未开始预留阻止额外领取;Start ACK 重报不重复计数。切换服务节点并 Resume 后窗口仍有效,两次实际 authorized_at 至少相隔一秒。
- 从两张在途许可降到并发 1、积压 1,不撤销在途执行;超过上限时不再领取。已领取 Start 限流后,用原消息在下一窗口成功,不增加尝试次数。
- 强制任务事件写入失败时回滚积压增加;明确失败后重试保持一个名额,UNKNOWN 耗尽后核查继续占名额;WAITING 截止及重复恢复只释放一次。
- 计划在积压 1 下只生成一条任务,游标停在下一原触发点;取消释放空间后下一批准确接续该触发点。
既有取消、结果 ACK 丢失、许可恢复及计划事务回归同步通过。额外的计数核对直接比较队列 counter 与任务真实状态集合,避免只检查返回 DTO。
[既有 v4 升级用例](../../internal/storage/mysql/retry_upgrade_integration_test.go) 继续走正式迁移到当前版本,新增验证 WAITING 和 NEEDS_REVIEW 合计回填为 2、默认上限 100000、原队列 revision=1 不变。旧任务各字段、策略、状态及重复迁移检查仍通过。[无外键升级用例](../../internal/storage/mysql/no_foreign_keys_integration_test.go) 同步验证当前外键为零及既有索引保留。
## 4. HTTP、SDK 和进程恢复
[SDK 用例](../../sdk/go/queue_resources_integration_test.go) 对真实 HTTP/WS 服务创建独立队列,验证省略 paused 被拒、429/QUEUE_FULL/RetryAfter、满额下重复受理回执、取消释放、原被拒身份重试、暂停期间不消耗尝试、恢复后自动 Worker 完成两个任务及精确整数保留。读取实际开始历史验证 rate=1 的授权间隔,最终 unfinished_tasks=0,运行计数不改变配置 revision。
[进程用例](../../sdk/go/worker_process_integration_test.go) 的 TestIntegrationWorkerProcessQueueBackpressure 在任务受理后强杀节点 A,Wait 确认退出,再启动不同身份的 B:新提交仍被满额拒绝,原身份仍返回原任务;取消释放后,之前被拒的新任务可用原身份受理。该过程没有修改额度或任务状态来模拟恢复。
完整资源示例输出 QUEUE_FULL/429、duplicate=true,最终两个任务 SUCCEEDED/attempts=1、unfinished=0、worker_drained=true。业务处理仅回显通用输入,无外部副作用。原有服务强杀、Worker 强杀转核查及两节点调度补跑回归也全部通过。
## 5. 边界与后续
一秒计数窗口允许窗口内突发,窗口交界可能出现短时聚集;不保证任意滑动一秒上限。限速针对平台开始授权,不限制业务处理器的内部请求。降低配置不回滚已有外部效果。
队列积压计数与任务写入在同一事务,直接绕过服务修改数据库可能造成漂移。尚无自动修复计数或硬删除入口;迁移回填要求停止旧服务及写入,未做大表在线回填验收。历史回执新增字段的兼容规则见接口手册。
当前验证同机进程、多节点身份及单 MySQL,尚未覆盖数据库复制切换、跨故障域、混合版本滚动升级、热点队列吞吐及百万租户容量。应用级配额、同业务键并发许可、优先级/公平性、可靠交付积压限制与保留清理仍需继续实现和回归;本阶段不等于 P3 或平台最终验收完成。