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

7.2 KiB
Raw Blame History

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-p0 02 execute 2
01-01
internal/task/polling_handler.go
pkg/queue/handler.go
true
CRITICAL-03
truths artifacts key_links
PollingHandler struct 有 asynqClient *asynq.Client 字段
NewPollingHandler 构造函数接受 asynqClient 参数
triggerFirstRealnameActivation 使用 asynqClient.EnqueueContext 入队,不再 RPush
_ = task 这行被删除
registerPollingHandlers 传入 h.asynqClient 给 NewPollingHandler
path provides contains
internal/task/polling_handler.go PollingHandler 注入 asynq.ClienttriggerFirstRealnameActivation 正确入队 asynqClient.EnqueueContext
path provides contains
pkg/queue/handler.go registerPollingHandlers 传入 asynqClient h.asynqClient
from to via pattern
pkg/queue/handler.go internal/task/polling_handler.go NewPollingHandler(h.db, h.redis, h.asynqClient, ...) NewPollingHandler
from to via pattern
internal/task/polling_handler.go asynq.Client h.asynqClient.EnqueueContext(ctx, task) asynqClient.EnqueueContext
修复实名激活任务断链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

<execution_context> @$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md @$HOME/.config/opencode/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/01-p0/01-01-SUMMARY.md @.planning/phases/01-p0/01-CONTEXT.md

修复规格书(方案 A-3第 165-299 行)

@.sisyphus/plans/修正业务-完整方案.md

```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  // ← 删掉
Task 1: PollingHandler 注入 asynqClientCRITICAL-03 internal/task/polling_handler.go, pkg/queue/handler.go **步骤 1修改 `internal/task/polling_handler.go` struct 定义**

在 PollingHandler struct第 31-42 行附近)新增字段:

type PollingHandler struct {
    db                    *gorm.DB
    redis                 *redis.Client
    asynqClient           *asynq.Client    // 新增
    gatewayClient         *gateway.Client
    // ... 其余字段不变
}

步骤 2修改 NewPollingHandler 构造函数签名(第 44 行附近)

新增 asynqClient *asynq.Client 参数位置redis 之后gatewayClient 之前):

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

// 删除这两行:
// 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 参数:

pollingHandler := task.NewPollingHandler(
    h.db,
    h.redis,
    h.asynqClient, // 新增Handler 结构体已有此字段
    h.gatewayClient,
    h.workerResult.Services.UsageService,
    h.logger,
)

修改完成后执行 go build ./...,确认编译通过,提交独立 commitper D-05。 go build ./... && rg "_ = task" internal/task/polling_handler.go && echo "FAIL: _ = task 仍存在" || echo "PASS: _ = task 已删除" - PollingHandler struct 含 asynqClient 字段 - NewPollingHandler 接受 asynqClient 参数 - triggerFirstRealnameActivation 使用 asynqClient.EnqueueContext不再 RPush - _ = task 这行已被删除 - pkg/queue/handler.go 传入 h.asynqClient - go build ./... 编译通过

整体验收:
# 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 日志:首次实名触发时应出现实名激活任务入队日志
  • DBHubSELECT id, status, pending_realname_activation, activated_at FROM tb_package_usage WHERE pending_realname_activation=true ORDER BY id DESC LIMIT 20;

<success_criteria>

  1. go build ./... 编译通过
  2. PollingHandler 有 asynqClient 字段且被正确初始化
  3. triggerFirstRealnameActivation 使用 EnqueueContext不再 RPush
  4. _ = task 行不存在
  5. 独立 commit 已提交 </success_criteria>
完成后创建 `.planning/phases/01-p0/01-02-SUMMARY.md`,记录: - 修改文件及改动说明 - 关键代码对比(修改前后) - 编译验证结果 - CRITICAL-03 完成状态