# P3 应用级配额与跨命名空间回归 验证日期:2026-09-17。本阶段补齐应用共享的未终结任务上限、执行并发及开始速率,同步 HTTP、独立 Go SDK、CLI 和双命名空间示例。P3 业务键许可、公平性及可靠订阅,以及 P4–P7 仍未完成,持续目标保持进行中。 ## 1. 交付范围 - [应用配额接口](../api/application-resources.md):读取当前应用额度及用量、显式应用管理权限、CAS/幂等管理、同事务审计和事件、降额保留在途任务。 - [ApplicationResources 模型](../../platform/model/application_resources.go) 与 000010 前向迁移:12 个持久化字段提供中文注释,SQL 同步 COMMENT,应用主键 BINARY(16),数据库外键仍为零,当前模型共 33 个。 - 受理、计划生成、领取、Start、取消、Finish、安全重试及到期恢复共同维护应用计数,跨命名空间与队列共享。空轮询与失败受理不消耗计数,重复回执不重复计费。 - 额度行与认证身份分离,统一按应用额度 → 队列 → 任务/尝试 → 许可顺序取锁;后台扫描跳过忙碌额度,应用停用后仍可释放到期尝试。 - 管理 CLI 支持 `--application-id` 在已有启用应用下增加命名空间;应用管理权限必须显式 `--resource-access`,普通队列及 Worker 凭据不扩权。 - [双命名空间 SDK 示例](../../examples/application-resources/main.go):第一侧受理,第二侧 APPLICATION_FULL,第一侧取消释放,第二侧原身份重报成功,取消收尾并按 CAS 恢复配置。 ## 2. 环境和实际回归 macOS 本机,Go 1.27.1,Docker MySQL 8.4.10;服务进程与数据库仅监听回环地址。使用随机凭据及一次性数据库,测试结束删除测试容器,没有修改已有业务数据库。 执行入口: ```sh make fmt test vet build make integration ``` 完整集成通过。测试分组的本次结果: | 分组 | 结果 | | --- | --- | | 全部数据库集成(含模型、无外键、配额、计划、执行及竞争) | PASS,68.475 秒 | | v9 应用计数回填与在途释放 | PASS,3.94 秒 | | v7 无外键升级、索引及数据保留 | PASS,3.85 秒 | | SDK Worker 连接、运行器、重试、取消和断线处理 | PASS,78.509 秒 | | SDK 计划生命周期 | PASS,含包开销 4.733 秒 | | SDK 队列资源控制 | PASS,含包开销 4.456 秒 | | SDK 双命名空间应用配额 | PASS,含包开销 1.401 秒 | | 原有真实进程故障组 | PASS,23.638 秒 | | 十个可运行示例 | 全部通过 | 十个示例为 health、tasks、worker-protocol、worker、history、retry、schedules、cancellation、resources、application-resources。上述用时仅为回归耗时,不是吞吐或容量结论。未配置集成环境的普通 `go test` 会跳过外部数据库及进程用例,实际证据来自已执行的集成入口。 本轮发现原计划版本边界用例使用宿主机时钟等待,而服务按数据库时间判定。用例改为从 MySQL 时间建立边界并等待真实数据库时刻,保留原版本、触发身份和结束状态断言;完整数据库回归随后通过。 ## 3. 配额与事务证据 [数据库用例](../../internal/storage/mysql/application_resources_integration_test.go) 覆盖: 1. 普通队列凭据读取及管理应用额度被拒绝;显式授权后同应用另一个命名空间可读聚合额度,其他应用保持独立。 2. 配置 CAS、同身份原快照重报、内容冲突;审计故障注入使配置、事件及幂等记录一起回滚,恢复后原身份可成功提交。 3. 两个命名空间各自队列同时发起 16 次受理,上限为 3 时仅 3 次成功;满额原成功回执仍可核对。降额至 1 不删已有任务,逐项取消后重新受理。 4. 队列已满和事件写入失败均不能泄漏应用额度;应用与队列计数同时回滚,原请求可以重报。 5. 两个节点/命名空间争用应用并发 1,仅一个取得尝试;预占取消释放未开始额度,成功结果及重复 Finish 不重复释放。 6. 预占后降低并发及开始速率,已有尝试保留;Start 事件故障回滚用量;原 Start ACK 重报不收费;未开始的预占跨窗口保留,不能被其他任务抢占。 7. 明确失败重试不重复占用积压,已开始失联保留未知效果及未完成额度,未开始到期和待执行截止释放空间。应用停用不阻止后台回收执行额度。 8. 定时计划遇到应用满额时保留未受理触发点,已生成的批次部分提交;释放空间后恢复同一原触发点,两级计数一致。 9. 一个应用额度行被显式持锁时,另一应用的恢复仍能推进;缺失、停用或参数歧义的应用不能由初始化 CLI 创建新命名空间。 所有计数断言同时查询真实任务状态进行核对,不只断言接口里的同一计数字段。 ## 4. 迁移和无外键 [应用额度升级测试](../../internal/storage/mysql/application_resources_upgrade_integration_test.go) 在隔离库建立有效任务、尝试、Worker 会话和许可,然后还原为 v9 结构再运行正式迁移: - 同一应用两个命名空间包含 WAITING、LEASED、RUNNING、NEEDS_REVIEW 和已成功任务,回填为 unfinished=4、active=2、pending=1;成功任务排除在外。 - 空应用三个用量均为零,配置默认值、版本与空窗口正确。 - 历史任务状态及版本不变;重复执行迁移不重算或覆盖当前计数。 - 迁移前已存在的预占取消和运行尝试完成后,共享用量正确变为 unfinished=2、active=0、pending=0。 v4 升级继续核对冻结策略、未知标记及应用未完成数。v7 无外键升级仍移除全部 70 个历史外键,已有 325 条索引列定义保留;新应用额度表自身主键另计。错误队列归属、错误会话关系及手工外键漂移继续被拒绝。 ## 5. SDK 与进程验证 [SDK 集成用例](../../sdk/go/application_resources_integration_test.go) 通过实际 HTTP 验证两个命名空间共享配置、普通队列管理员无应用权限、跨命名空间幂等键空间独立、错误字段及应用归属覆盖被拒绝。第二侧收到 HTTP 429 / APPLICATION_FULL / Retry-After: 1;第一侧释放后,原键提交成功,最终三个用量为零。 示例实际输出: ```text cross_namespace_backpressure=APPLICATION_FULL http=429 same_identity_retry_accepted=true unfinished=0 active=0 pending_starts=0 ``` 原有服务 ACK 丢失接管、Worker 强杀后未知核查、计划强杀补跑和队列背压进程用例同步通过。 最后定向回归新增的额度泄漏断言与应用强杀场景也通过:数据库应用配额九组场景 10.24 秒(含包开销 11.572 秒),SDK 应用配额 0.15 秒,完整示例再次通过;`TestIntegrationWorkerProcessApplicationBackpressure` 0.14 秒(含包开销 1.818 秒)。该场景强杀并 Wait 确认旧服务退出,再启动不同 node_id:共享上限和未完成计数保留,原受理回执可重放,另一个命名空间继续被全局满额拒绝,原任务取消后才能用被拒原键受理。这项证明应用受理额度跨进程持久化,不将它扩大为全部数据库故障模型或开始速率窗口的进程验收。 文档校验通过 320 个本地链接及 26 个 JSON 示例;269 个直接声明的持久化字段全部有中文注释。 ## 6. 当前边界 - 共享配额限于同一 MySQL 主库。单个应用的额度行是串行化点,必须在生产容量阶段测锁等待、吞吐、续租与恢复延迟;没有宣称百万租户容量或跨库原子配额。 - 开始限流为固定一秒窗口,允许边界突发;控制的是平台授权次数,不是处理器内部业务请求。 - 停止旧写入节点后迁移再启动新版,不能与不维护应用用量的旧节点混跑。大表回填和混合版本在线升级未验收。 - 数据库关联依靠服务端事务,没有外键;直接 SQL 修改归属或删除额度记录不属于支持的业务操作。 - 本轮为单数据库、多服务进程及故障注入验证;数据库复制切换、跨故障域网络分区、备份恢复、实际 RPO/RTO 和峰值容量仍在 P6。