feat: 实现 MySQL 租约队列与 CAS 状态机 #9

Closed
opened 2026-08-20 18:01:02 +08:00 by ila · 0 comments
Owner

基本信息

  • 类型:需求
  • 所属 Epic:#3
  • 所属 MVP / 版本:#4(MVP-0)
  • 阶段:已完成

依赖与并行

  • 前置工单:#6、#7
  • 是否允许与前置工单并行:否
  • 原因:依赖项定义本工单所需的可执行环境、共享模型、接口或已确认设计;未满足时保持待实施,不标记阻塞。

子项目影响

  • 仅影响的子项目 / 交付单元:internal/core/queue、MySQL 仓储
  • 是否跨子项目:是
  • 是否修改共享接口或契约:是;实现 generation 状态和租约持久化契约
  • 各子项目需要执行的验证:见“验证方式”和验收标准。

原始需求

  • 来源:用户对话;Product-Requirements-Overview、Architecture-and-Code-Map、Business-Rules-and-Glossary
  • 提出时间:2026-08-20
  • 关键原话或脱敏摘要:用户要求“为 MVP-0 的生产实现拆分单元工单”;本工单负责 实现 MySQL 8 SKIP LOCKED 租约队列、attempt 原子记录和最终 CAS。

要解决什么

MVP-0 不使用 Redis/MQ,必须依靠 MySQL 8 在并发 worker 下安全认领、恢复过期任务并阻止陈旧 worker 覆盖新结果。

做什么 / 不做什么

做

  • 事务内用 FOR UPDATE SKIP LOCKED 选择 pending 或租约过期的 running。
  • 原子写 running、lease_owner/token/until 和 attempt_count,并追加脱敏 attempt。
  • 过期 running 只替换租约,不回退 pending;最终成功/失败更新匹配 id、running 和 token。
  • 实现相同用户 idempotency_key 返回原任务的仓储操作,不重复写上传元数据。
  • 支持优雅退出时停止取新任务,在途任务超期后让租约自然过期。

不做

  • 不调用上游、不处理 HTTP/session/文件内容,不引入 Redis/MQ。
  • 不实现心跳续租、多 Provider 故障转移、清理任务或无限重试。
  • 不修改 retryable 规则和已确认状态机。

已确认方案

  • claim、attempt 和租约变更保持事务/原子一致。
  • 旧 token 最终 CAS 影响 0 行被视为所有权丢失,不重试覆盖。
  • lease 时长是配置且上线前确认;测试使用显式短值,不冒充生产值。

预计修改文件:

  • internal/core/queue/
  • MySQL 仓储实现及同目录测试
  • 必要的测试 fixture,不含真实数据

需求变化记录

  • 2026-08-20:采用 MySQL NOW(6) 作为租约比较/写入时钟,避免应用时钟偏差;同用户幂等创建通过事务锁定 users 行串行化,不依赖驱动特定错误解析。claim 追加 attempt 起始项,最终 CAS 替换该项并与输出/失败状态同事务提交。实现中若范围、接口、数据、依赖、验收或风险发生变化,必须先更新本工单;改变已确认结果时重新等待用户确认。

设计与原型门禁

  • 修改类型:非 UI
  • 所需设计证据:已确认的架构、数据、安全或流程设计;不要求 UI 原型
  • 事实来源:核心 Wiki 与父工单 #4
  • 状态:已确认;具体实现差异仍须按工单变化规则处理
  • 无需 UI 原型原因:本工单不改变用户界面

文档影响

  • 不影响长期文档
  • 按实际变化更新 Project-Profile、Architecture-and-Code-Map、Local-Development-and-Verification、Deployment-and-Operations 或 Business-Rules-and-Glossary
  • Wiki 先改、在线回读后再同步 docs/,不得直接维护镜像

交付文档影响

  • 无交付文档影响,原因:内部实现任务;若实际改变部署、配置或支持方式,执行前更新本项
  • 更新已有交付文档
  • 新增交付文档

验收标准

  • 两个并发 worker 不会认领同一有效任务。
  • 过期 running 被新 token 原子重领,状态不回退 pending。
  • 旧 token 成功/失败写入均影响 0 行且不覆盖新结果。
  • attempt_count、attempts、error_code/error_message 与状态更新保持一致且内容脱敏限长。
  • 同用户幂等重放返回原任务,不同用户相同键互不冲突。
  • 优雅退出停止取新任务且不无条件提交失去租约的结果。

验证方式

  • go test ./internal/core/queue/...
  • MySQL 8 隔离库并发集成测试与 go test -race
  • 租约过期、陈旧 token、幂等和事务回滚故障注入

未执行或因环境不足无法执行的验证必须如实回写,不得把预期结果记为通过。

风险和回退

  • 高风险:并发与事务错误可能造成重复上游调用或覆盖结果;必须使用真实 MySQL 8 集成测试,mock SQL 不算全部通过。
  • 风险:隔离级别和连接池影响 SKIP LOCKED;在测试中显式记录实际配置。
  • 回退:停止 worker,回退队列实现提交;schema 回退只走已验证迁移。

实施与验证证据(2026-08-21)

  • 实现提交:7dfb52816625b6d1c595961651ed9d0bac89b893;文档提交:d61d73d96fa4472fae0007aa4d805cf950d1d643,均已推送到 origin/main。
  • 本机隔离 MySQL 8.4.8,事务隔离级别 REPEATABLE-READ;迁移版本 1,dirty=0。
  • 已通过真实 MySQL 并发认领、租约过期重领、旧 token CAS、attempt 链、幂等和输出回滚集成测试,并通过 go test -race。
  • 核心 Wiki 已在线回读并同步镜像:Architecture revision 27a47e30cb5d79f6a6146e067a20296e850f8ab;Local Development revision 52051ea9898e7ee1b4f502cb77906aa105163ce7。
  • 任务归档:Task-9-实现-MySQL-8-SKIP-LOCKED-租约队列、attempt-原子记录和最终-CAS,revision 44666439fa9c367634564337887080fe334f208b。
  • 未调用真实上游;测试数据已清理。工单保持开启,等待人工验收。

验收结论

  • 用户于 2026-08-21 明确确认 #9 验收通过。
  • MVP-0 单元验收文档提交:919e11f,已推送到 main。
  • 任务归档 revision:80fb8f8d4b4d。
## 基本信息 - 类型:需求 - 所属 Epic:#3 - 所属 MVP / 版本:#4(MVP-0) - 阶段:已完成 ## 依赖与并行 - 前置工单:#6、#7 - 是否允许与前置工单并行:否 - 原因:依赖项定义本工单所需的可执行环境、共享模型、接口或已确认设计;未满足时保持待实施,不标记阻塞。 ## 子项目影响 - 仅影响的子项目 / 交付单元:internal/core/queue、MySQL 仓储 - 是否跨子项目:是 - 是否修改共享接口或契约:是;实现 generation 状态和租约持久化契约 - 各子项目需要执行的验证:见“验证方式”和验收标准。 ## 原始需求 - 来源:用户对话;Product-Requirements-Overview、Architecture-and-Code-Map、Business-Rules-and-Glossary - 提出时间:2026-08-20 - 关键原话或脱敏摘要:用户要求“为 MVP-0 的生产实现拆分单元工单”;本工单负责 实现 MySQL 8 SKIP LOCKED 租约队列、attempt 原子记录和最终 CAS。 ## 要解决什么 MVP-0 不使用 Redis/MQ,必须依靠 MySQL 8 在并发 worker 下安全认领、恢复过期任务并阻止陈旧 worker 覆盖新结果。 ## 做什么 / 不做什么 ### 做 - 事务内用 `FOR UPDATE SKIP LOCKED` 选择 pending 或租约过期的 running。 - 原子写 running、lease_owner/token/until 和 attempt_count,并追加脱敏 attempt。 - 过期 running 只替换租约,不回退 pending;最终成功/失败更新匹配 id、running 和 token。 - 实现相同用户 idempotency_key 返回原任务的仓储操作,不重复写上传元数据。 - 支持优雅退出时停止取新任务,在途任务超期后让租约自然过期。 ### 不做 - 不调用上游、不处理 HTTP/session/文件内容,不引入 Redis/MQ。 - 不实现心跳续租、多 Provider 故障转移、清理任务或无限重试。 - 不修改 retryable 规则和已确认状态机。 ## 已确认方案 - claim、attempt 和租约变更保持事务/原子一致。 - 旧 token 最终 CAS 影响 0 行被视为所有权丢失,不重试覆盖。 - lease 时长是配置且上线前确认;测试使用显式短值,不冒充生产值。 预计修改文件: - `internal/core/queue/` - MySQL 仓储实现及同目录测试 - 必要的测试 fixture,不含真实数据 ## 需求变化记录 - 2026-08-20:采用 MySQL `NOW(6)` 作为租约比较/写入时钟,避免应用时钟偏差;同用户幂等创建通过事务锁定 `users` 行串行化,不依赖驱动特定错误解析。claim 追加 attempt 起始项,最终 CAS 替换该项并与输出/失败状态同事务提交。实现中若范围、接口、数据、依赖、验收或风险发生变化,必须先更新本工单;改变已确认结果时重新等待用户确认。 ## 设计与原型门禁 - 修改类型:非 UI - 所需设计证据:已确认的架构、数据、安全或流程设计;不要求 UI 原型 - 事实来源:核心 Wiki 与父工单 #4 - 状态:已确认;具体实现差异仍须按工单变化规则处理 - 无需 UI 原型原因:本工单不改变用户界面 ## 文档影响 - [ ] 不影响长期文档 - [x] 按实际变化更新 Project-Profile、Architecture-and-Code-Map、Local-Development-and-Verification、Deployment-and-Operations 或 Business-Rules-and-Glossary - Wiki 先改、在线回读后再同步 `docs/`,不得直接维护镜像 ## 交付文档影响 - [x] 无交付文档影响,原因:内部实现任务;若实际改变部署、配置或支持方式,执行前更新本项 - [ ] 更新已有交付文档 - [ ] 新增交付文档 ## 验收标准 - [x] 两个并发 worker 不会认领同一有效任务。 - [x] 过期 running 被新 token 原子重领,状态不回退 pending。 - [x] 旧 token 成功/失败写入均影响 0 行且不覆盖新结果。 - [x] attempt_count、attempts、error_code/error_message 与状态更新保持一致且内容脱敏限长。 - [x] 同用户幂等重放返回原任务,不同用户相同键互不冲突。 - [x] 优雅退出停止取新任务且不无条件提交失去租约的结果。 ## 验证方式 - `go test ./internal/core/queue/...` - MySQL 8 隔离库并发集成测试与 `go test -race` - 租约过期、陈旧 token、幂等和事务回滚故障注入 未执行或因环境不足无法执行的验证必须如实回写,不得把预期结果记为通过。 ## 风险和回退 - 高风险:并发与事务错误可能造成重复上游调用或覆盖结果;必须使用真实 MySQL 8 集成测试,mock SQL 不算全部通过。 - 风险:隔离级别和连接池影响 SKIP LOCKED;在测试中显式记录实际配置。 - 回退:停止 worker,回退队列实现提交;schema 回退只走已验证迁移。 ## 实施与验证证据(2026-08-21) - 实现提交:7dfb52816625b6d1c595961651ed9d0bac89b893;文档提交:d61d73d96fa4472fae0007aa4d805cf950d1d643,均已推送到 origin/main。 - 本机隔离 MySQL 8.4.8,事务隔离级别 REPEATABLE-READ;迁移版本 1,dirty=0。 - 已通过真实 MySQL 并发认领、租约过期重领、旧 token CAS、attempt 链、幂等和输出回滚集成测试,并通过 go test -race。 - 核心 Wiki 已在线回读并同步镜像:Architecture revision 27a47e30cb5d79f6a6146e067a20296e850f8ab;Local Development revision 52051ea9898e7ee1b4f502cb77906aa105163ce7。 - 任务归档:Task-9-实现-MySQL-8-SKIP-LOCKED-租约队列、attempt-原子记录和最终-CAS,revision 44666439fa9c367634564337887080fe334f208b。 - 未调用真实上游;测试数据已清理。工单保持开启,等待人工验收。 ## 验收结论 - 用户于 2026-08-21 明确确认 #9 验收通过。 - MVP-0 单元验收文档提交:`919e11f`,已推送到 `main`。 - 任务归档 revision:`80fb8f8d4b4d`。
ila closed this issue 2026-08-21 11:59:14 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/chorus#9