Files
junhong_cmp_fiber/.planning/phases/01-p0/01-02-PLAN.md

226 lines
7.2 KiB
Markdown
Raw 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.
---
phase: 01-p0
plan: 02
type: execute
wave: 2
depends_on:
- 01-01
files_modified:
- internal/task/polling_handler.go
- pkg/queue/handler.go
autonomous: true
requirements:
- CRITICAL-03
must_haves:
truths:
- "PollingHandler struct 有 asynqClient *asynq.Client 字段"
- "NewPollingHandler 构造函数接受 asynqClient 参数"
- "triggerFirstRealnameActivation 使用 asynqClient.EnqueueContext 入队,不再 RPush"
- "_ = task 这行被删除"
- "registerPollingHandlers 传入 h.asynqClient 给 NewPollingHandler"
artifacts:
- path: internal/task/polling_handler.go
provides: "PollingHandler 注入 asynq.ClienttriggerFirstRealnameActivation 正确入队"
contains: "asynqClient.EnqueueContext"
- path: pkg/queue/handler.go
provides: "registerPollingHandlers 传入 asynqClient"
contains: "h.asynqClient"
key_links:
- from: pkg/queue/handler.go
to: internal/task/polling_handler.go
via: "NewPollingHandler(h.db, h.redis, h.asynqClient, ...)"
pattern: "NewPollingHandler"
- from: internal/task/polling_handler.go
to: asynq.Client
via: "h.asynqClient.EnqueueContext(ctx, task)"
pattern: "asynqClient\\.EnqueueContext"
---
<objective>
修复实名激活任务断链CRITICAL-03为 PollingHandler 注入 asynq.Client删除 RPush 降级方案,改用正式 Asynq 入队。
Purpose: 首次实名后自动激活"囤货套餐"的完整链路当前完全断裂——task 被 `_ = task` 丢弃,实际走 Redis RPush 降级,但无消费者消费这个列表。修复后套餐激活任务正常进入 Asynq 队列被消费。
Output:
- polling_handler.go: 新增 asynqClient 字段triggerFirstRealnameActivation 改为 EnqueueContext
- pkg/queue/handler.go: registerPollingHandlers 传入 h.asynqClient
</objective>
<execution_context>
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
@$HOME/.config/opencode/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/phases/01-p0/01-01-SUMMARY.md
@.planning/phases/01-p0/01-CONTEXT.md
# 修复规格书(方案 A-3第 165-299 行)
@.sisyphus/plans/修正业务-完整方案.md
<interfaces>
<!-- pkg/queue/handler.go Handler struct 已有 asynqClient 字段 -->
```go
// pkg/queue/handler.go Handler struct已存在
type Handler struct {
db *gorm.DB
redis *redis.Client
asynqClient *asynq.Client // ← 已有此字段,直接传给 NewPollingHandler
// ...
}
// registerPollingHandlers 当前调用(需修改)
pollingHandler := task.NewPollingHandler(
h.db,
h.redis,
// h.asynqClient ← 缺少此行
h.gatewayClient,
h.workerResult.Services.UsageService,
h.logger,
)
```
<!-- polling_handler.go 当前错误代码triggerFirstRealnameActivation 第 1100 行) -->
```go
// 当前降级代码(需删除 RPush 部分,直接用 EnqueueContext
task := asynq.NewTask(constants.TaskTypePackageFirstActivation, payloadBytes, ...)
activationKey := constants.RedisPollingManualQueueKey(constants.TaskTypePackageFirstActivation)
h.redis.RPush(ctx, activationKey, string(payloadBytes)) // ← 删掉
_ = task // ← 删掉
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: PollingHandler 注入 asynqClientCRITICAL-03</name>
<files>internal/task/polling_handler.go, pkg/queue/handler.go</files>
<action>
**步骤 1修改 `internal/task/polling_handler.go` struct 定义**
在 PollingHandler struct第 31-42 行附近)新增字段:
```go
type PollingHandler struct {
db *gorm.DB
redis *redis.Client
asynqClient *asynq.Client // 新增
gatewayClient *gateway.Client
// ... 其余字段不变
}
```
**步骤 2修改 NewPollingHandler 构造函数签名(第 44 行附近)**
新增 `asynqClient *asynq.Client` 参数位置redis 之后gatewayClient 之前):
```go
func NewPollingHandler(
db *gorm.DB,
redis *redis.Client,
asynqClient *asynq.Client, // 新增
gatewayClient *gateway.Client,
usageService *packagepkg.UsageService,
logger *zap.Logger,
) *PollingHandler {
return &PollingHandler{
db: db,
redis: redis,
asynqClient: asynqClient, // 新增
gatewayClient: gatewayClient,
// ... 其余字段不变
}
}
```
**步骤 3修改 triggerFirstRealnameActivation第 1100 行附近)**
删除 RPush 降级代码,改为 EnqueueContext
```go
// 删除这两行:
// activationKey := constants.RedisPollingManualQueueKey(constants.TaskTypePackageFirstActivation)
// h.redis.RPush(ctx, activationKey, string(payloadBytes))
// _ = task
// 替换为:
if _, err := h.asynqClient.EnqueueContext(ctx, task); err != nil {
h.logger.Warn("提交首次实名激活任务失败",
zap.Uint("package_usage_id", pkg.ID),
zap.Error(err))
continue
}
```
注意:`task` 变量已在上方声明,不需要重新创建。
**步骤 4修改 `pkg/queue/handler.go:registerPollingHandlers`(第 151 行附近)**
在 NewPollingHandler 调用中补充 `h.asynqClient` 参数:
```go
pollingHandler := task.NewPollingHandler(
h.db,
h.redis,
h.asynqClient, // 新增Handler 结构体已有此字段
h.gatewayClient,
h.workerResult.Services.UsageService,
h.logger,
)
```
修改完成后执行 `go build ./...`,确认编译通过,提交独立 commitper D-05
</action>
<verify>
<automated>go build ./... && rg "_ = task" internal/task/polling_handler.go && echo "FAIL: _ = task 仍存在" || echo "PASS: _ = task 已删除"</automated>
</verify>
<done>
- PollingHandler struct 含 asynqClient 字段
- NewPollingHandler 接受 asynqClient 参数
- triggerFirstRealnameActivation 使用 asynqClient.EnqueueContext不再 RPush
- _ = task 这行已被删除
- pkg/queue/handler.go 传入 h.asynqClient
- go build ./... 编译通过
</done>
</task>
</tasks>
<verification>
整体验收:
```bash
# 1. 编译验证
go build ./...
# 2. 确认降级代码已删除
rg "_ = task" internal/task/polling_handler.go
rg "RPush.*TaskTypePackageFirstActivation\|RedisPollingManualQueueKey" internal/task/polling_handler.go
# 3. 确认正确入队代码存在
rg "asynqClient.EnqueueContext" internal/task/polling_handler.go
# 4. 确认 registerPollingHandlers 传了 asynqClient
rg "NewPollingHandler" pkg/queue/handler.go
```
人工验收(参见修正业务-完整方案.md A-3 验收清单):
- Worker 日志:首次实名触发时应出现实名激活任务入队日志
- DBHub`SELECT id, status, pending_realname_activation, activated_at FROM tb_package_usage WHERE pending_realname_activation=true ORDER BY id DESC LIMIT 20;`
</verification>
<success_criteria>
1. `go build ./...` 编译通过
2. PollingHandler 有 asynqClient 字段且被正确初始化
3. triggerFirstRealnameActivation 使用 EnqueueContext不再 RPush
4. `_ = task` 行不存在
5. 独立 commit 已提交
</success_criteria>
<output>
完成后创建 `.planning/phases/01-p0/01-02-SUMMARY.md`,记录:
- 修改文件及改动说明
- 关键代码对比(修改前后)
- 编译验证结果
- CRITICAL-03 完成状态
</output>