All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m54s
- 拆分订单创建为 CreateAdminOrder(后台一步支付)和 CreateH5Order(H5 两步支付) - 新增 CreateAdminOrderRequest DTO,后台仅允许 wallet/offline 支付方式 - 同步 delta specs 到主规格(order-payment 更新 + admin-order-creation 新增) - 归档 fix-agent-wallet-order-creation 变更 - 新增 implement-order-expiration 变更提案
13 KiB
13 KiB
1. 数据库迁移
- 1.1 创建迁移文件
migrations/000xxx_add_order_expiration.up.sql:添加expires_at字段和复合索引idx_order_expires(expires_at, payment_status) - 1.2 创建回滚文件
migrations/000xxx_add_order_expiration.down.sql:删除索引和字段 - 1.3 执行迁移验证:运行
migrate up并检查表结构,确认字段和索引创建成功 - 1.4 测试回滚:运行
migrate down并验证字段和索引删除成功,然后重新migrate up
2. 常量定义
- 2.1 在
pkg/constants/constants.go中添加订单超时时间常量OrderExpireTimeout = 30 * time.Minute - 2.2 在
pkg/constants/constants.go中添加任务类型常量TaskTypeOrderExpire = "order:expire" - 2.3 在
pkg/constants/constants.go中添加批量处理数量常量OrderExpireBatchSize = 100 - 2.4 验证编译:运行
go build ./...确认无编译错误
3. Model 层修改
- 3.1 在
internal/model/order.go中的Order结构体添加ExpiresAt *time.Time字段(指针类型,支持 NULL) - 3.2 在
internal/model/dto/order_dto.go中的OrderResponse添加ExpiresAt *time.Time和IsExpired bool字段 - 3.3 验证编译:运行
go build ./internal/model/...确认无编译错误
4. Store 层新增方法
- 4.1 在
internal/store/postgres/order_store.go添加FindExpiredOrders(ctx, limit int) ([]*model.Order, error)方法:查询expires_at <= NOW() AND payment_status = 1的订单 - 4.2 在
internal/store/postgres/order_store.go的UpdatePaymentStatus()方法中添加expiresAt *time.Time参数,支持更新过期时间 - 4.3 验证编译:运行
go build ./internal/store/...确认无编译错误 - 4.4 使用 PostgreSQL MCP 工具验证查询:执行
FindExpiredOrders的 SQL,确认索引使用正确且查询耗时 < 50ms
5. Service 层修改 - 订单创建
- 5.1 修改
internal/service/order/service.go的Create()方法:待支付订单设置expires_at = now + 30min - 5.2 修改
Create()方法:后台钱包一步支付订单和线下支付订单expires_at = nil - 5.3 验证编译:运行
go build ./internal/service/order/...确认无编译错误
6. Service 层修改 - 订单取消和钱包解冻
- 6.1 修改
internal/service/order/service.go的Cancel()方法:添加钱包解冻逻辑(判断支付方式,计算解冻金额) - 6.2 在
Cancel()方法中添加事务处理:订单状态更新(payment_status = 3,expires_at = nil)和钱包解冻在同一事务 - 6.3 在
Cancel()方法中添加解冻规则判断逻辑:钱包支付(H5)、混合支付需解冻,纯在线支付不解冻 - 6.4 验证编译:运行
go build ./internal/service/order/...确认无编译错误
7. Service 层新增方法 - 批量取消超时订单
- 7.1 在
internal/service/order/service.go添加CancelExpiredOrders(ctx context.Context) (int, error)方法 - 7.2 实现
CancelExpiredOrders()逻辑:调用FindExpiredOrders()查询超时订单(最多 100 条) - 7.3 实现批量取消逻辑:遍历订单,调用
Cancel()方法(复用钱包解冻逻辑) - 7.4 添加日志记录:处理订单数量、解冻钱包次数、执行耗时
- 7.5 验证编译:运行
go build ./internal/service/order/...确认无编译错误
8. Service 层修改 - 支付成功清除过期时间
- 8.1 修改
internal/service/order/service.go的WalletPay()方法:调用UpdatePaymentStatus()时传入expiresAt = nil - 8.2 修改
HandlePaymentCallback()方法:调用UpdatePaymentStatus()时传入expiresAt = nil - 8.3 验证编译:运行
go build ./internal/service/order/...确认无编译错误
9. Task 层新增定时任务
- 9.1 创建
internal/task/order_expire.go文件,定义OrderExpireHandler结构体 - 9.2 实现
NewOrderExpireHandler()构造函数,依赖注入db,orderService,logger - 9.3 实现
HandleOrderExpire(ctx context.Context, task *asynq.Task) error方法,调用orderService.CancelExpiredOrders() - 9.4 添加错误处理和重试逻辑:可重试错误返回
err,不可重试错误返回asynq.SkipRetry - 9.5 添加日志记录:任务开始、成功处理订单数、失败错误
- 9.6 验证编译:运行
go build ./internal/task/...确认无编译错误
10. Worker 注册定时任务 Handler
- 10.1 在
pkg/queue/handler.go的RegisterHandlers()方法中调用registerOrderExpireHandler() - 10.2 实现
registerOrderExpireHandler()方法:创建OrderExpireHandler并注册到mux.HandleFunc(constants.TaskTypeOrderExpire, ...) - 10.3 验证编译:运行
go build ./pkg/queue/...确认无编译错误
11. Worker 创建和启动 Asynq Scheduler
- 11.1 在
cmd/worker/main.go中创建 Asynq Scheduler 实例:asynq.NewScheduler(redisOpt, &asynq.SchedulerOpts{Location: time.Local}) - 11.2 注册订单超时周期任务:
scheduler.Register("@every 1m", asynq.NewTask(constants.TaskTypeOrderExpire, nil), asynq.Queue(constants.QueueDefault)) - 11.3 启动 Scheduler:
scheduler.Start(),并在 defer 中调用scheduler.Shutdown() - 11.4 验证编译:运行
go build ./cmd/worker/...确认无编译错误
12. Handler 层修改 - DTO 响应
- 12.1 修改
internal/handler/admin/order.go和internal/handler/h5/order.go的订单响应构建逻辑:添加ExpiresAt字段 - 12.2 实现
IsExpired动态计算逻辑:if expiresAt != nil && paymentStatus == 1 { isExpired = now.After(expiresAt) } - 12.3 验证编译:运行
go build ./internal/handler/...确认无编译错误
13. Handler 层修改 - 查询过期状态
- 13.1 修改
internal/model/dto/order_dto.go的ListOrderRequest添加IsExpired *bool查询参数(可选) - 13.2 修改
internal/store/postgres/order_store.go的List()方法:添加过期状态筛选条件(is_expired = true映射为expires_at <= NOW() AND payment_status = 1) - 12.3 验证编译:运行
go build ./...确认无编译错误
14. 功能验证 - 订单创建
- 14.1 启动 API 服务,使用 Postman/curl 创建待支付订单(H5 端,支付方式 wechat),验证
expires_at字段设置正确(约now + 30min) - 14.2 使用 PostgreSQL MCP 工具查询订单:
SELECT id, expires_at, payment_status FROM tb_order WHERE id = ?,确认expires_at不为 NULL - 14.3 创建后台钱包支付订单,验证
expires_at为 NULL(订单立即支付成功)
15. 功能验证 - 订单取消和钱包解冻
- 15.1 创建混合支付待支付订单(钱包预扣 2000 分),使用 PostgreSQL MCP 查询钱包冻结余额
- 15.2 调用取消订单 API,验证订单状态变更为已取消(
payment_status = 3),expires_at变更为 NULL - 15.3 使用 PostgreSQL MCP 查询钱包:确认冻结余额减少 2000 分
- 15.4 创建纯在线支付订单(wechat),取消订单,确认不执行钱包解冻操作
16. 功能验证 - 支付成功清除过期时间
- 16.1 创建待支付订单(wechat),确认
expires_at不为 NULL - 16.2 模拟第三方支付回调成功,验证订单状态变更为已支付(
payment_status = 2),expires_at变更为 NULL - 16.3 使用 PostgreSQL MCP 查询订单:
SELECT id, expires_at, payment_status FROM tb_order WHERE id = ?,确认expires_at为 NULL
17. 功能验证 - 定时任务自动取消
- 17.1 使用 PostgreSQL MCP 手动修改订单的
expires_at为过去时间:UPDATE tb_order SET expires_at = NOW() - INTERVAL '1 minute' WHERE id = ? - 17.2 启动 Worker 服务,等待 1 分钟后检查日志,确认定时任务执行成功
- 17.3 使用 PostgreSQL MCP 查询订单:确认订单状态变更为已取消,
expires_at变更为 NULL - 17.4 如果是混合支付订单,使用 PostgreSQL MCP 查询钱包:确认冻结余额解冻
18. 功能验证 - 查询过期状态
- 18.1 使用 Postman/curl 调用订单列表 API,筛选
is_expired = true,验证返回已过期的待支付订单 - 18.2 调用订单列表 API,筛选
is_expired = false,验证返回未过期的待支付订单 - 18.3 调用订单详情 API,验证响应包含
is_expired字段且计算正确
19. 性能验证
- 19.1 使用 PostgreSQL MCP 的
explain_query工具分析FindExpiredOrders查询:确认使用idx_order_expires索引 - 19.2 验证查询耗时:在订单数量 > 10000 的情况下,查询耗时 < 50ms
- 19.3 验证定时任务处理耗时:单批次处理 100 条订单,总耗时 < 5s
- 19.4 使用 PostgreSQL MCP 检查数据库连接池状态:确认无连接池阻塞
20. 错误处理验证
- 20.1 模拟数据库连接失败场景:确认定时任务返回可重试错误,Asynq 自动重试
- 20.2 模拟钱包不存在场景:确认订单取消失败,事务回滚,订单状态不变
- 20.3 模拟冻结余额不足场景:确认订单取消失败,事务回滚,记录错误日志
- 20.4 检查日志:确认所有错误场景都记录了详细日志(包含订单 ID、错误原因)
21. 代码质量检查
- 21.1 运行
gofmt -s -w .格式化代码 - 21.2 运行
go vet ./...检查代码问题 - 21.3 运行
go build ./...确认全部编译通过 - 21.4 检查所有新增代码的中文注释:确认符合注释规范(导出符号有文档注释,复杂逻辑有实现注释)
22. 文档更新
- 22.1 创建功能总结文档
docs/order-expiration/功能总结.md:说明超时机制、钱包解冻、查询过期状态 - 22.2 更新
README.md:在"已实现功能"部分添加"订单超时自动失效" - 22.3 更新
openspec/specs/iot-order/spec.md:同步 delta spec 到主规格文档(归档后) - 22.4 更新
openspec/specs/order-payment/spec.md:同步 delta spec 到主规格文档(归档后)
23. 最终验证
- 23.1 在开发环境完整测试一次完整流程:创建订单 → 超时自动取消 → 钱包解冻
- 23.2 检查所有日志输出:确认日志级别正确(Info/Error),日志内容完整
- 23.3 检查数据库:确认无脏数据(如订单已取消但钱包未解冻)
- 23.4 使用 Postman 导出 API 测试用例集(包含订单创建、取消、查询过期状态)
24. 重构现有定时任务为 Asynq Scheduler
- 24.1 在
pkg/constants/constants.go中添加告警检查任务类型常量TaskTypeAlertCheck = "alert:check" - 24.2 在
pkg/constants/constants.go中添加数据清理任务类型常量TaskTypeDataCleanup = "data:cleanup" - 24.3 创建
internal/task/alert_check.go文件,定义AlertCheckHandler结构体 - 24.4 实现
NewAlertCheckHandler()构造函数,依赖注入alertService,logger - 24.5 实现
HandleAlertCheck(ctx context.Context, task *asynq.Task) error方法,调用alertService.CheckAlerts() - 24.6 创建
internal/task/data_cleanup.go文件,定义DataCleanupHandler结构体 - 24.7 实现
NewDataCleanupHandler()构造函数,依赖注入cleanupService,logger - 24.8 实现
HandleDataCleanup(ctx context.Context, task *asynq.Task) error方法,调用cleanupService.RunScheduledCleanup() - 24.9 在
pkg/queue/handler.go的RegisterHandlers()方法中调用registerAlertCheckHandler() - 24.10 实现
registerAlertCheckHandler()方法:创建AlertCheckHandler并注册到mux.HandleFunc(constants.TaskTypeAlertCheck, ...) - 24.11 在
pkg/queue/handler.go的RegisterHandlers()方法中调用registerDataCleanupHandler() - 24.12 实现
registerDataCleanupHandler()方法:创建DataCleanupHandler并注册到mux.HandleFunc(constants.TaskTypeDataCleanup, ...) - 24.13 在
cmd/worker/main.go的 Asynq Scheduler 中注册告警检查周期任务:scheduler.Register("@every 1m", asynq.NewTask(constants.TaskTypeAlertCheck, nil)) - 24.14 在
cmd/worker/main.go的 Asynq Scheduler 中注册数据清理周期任务:scheduler.Register("0 2 * * *", asynq.NewTask(constants.TaskTypeDataCleanup, nil))(每天凌晨2点) - 24.15 移除
cmd/worker/main.go中的startAlertChecker函数定义(第 239-265 行) - 24.16 移除
cmd/worker/main.go中的startCleanupScheduler函数定义(第 267-303 行) - 24.17 移除
cmd/worker/main.go中对startAlertChecker和startCleanupScheduler的调用和相关代码 - 24.18 验证编译:运行
go build ./cmd/worker/...确认无编译错误 - 24.19 验证编译:运行
go build ./internal/task/...确认无编译错误 - 24.20 验证编译:运行
go build ./pkg/queue/...确认无编译错误
25. 提交和归档
- 25.1 使用
/commit创建 Git commit,提交消息:"实现订单超时自动失效机制并重构定时任务为 Asynq Scheduler" - 25.2 使用
/opsx:verify验证实现与规格一致 - 25.3 使用
/opsx:archive归档变更,同步 delta specs 到主规格文档 - 25.4 确认归档后
openspec/specs/iot-order/spec.md和openspec/specs/order-payment/spec.md已更新