--- doc_type: refactor-design refactor: 2026-04-25-backend-cleanup status: approved scope: 后端 Go 代码全部(internal/、pkg/、cmd/),21 文件 ~2485 行 summary: 执行 11 条低中风险重构:6 条提取函数消除重复、2 条性能修复(递归改迭代、锁优化)、3 条小修(typo、删除死代码、内存泄漏) --- # backend-cleanup refactor design ## 1. 本次范围 - 勾选:#1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #12 - 明确不做:#11(Handler 层业务逻辑下沉——高风险、跨模块,建议单独开一轮 refactor) - 预估总工作量:小 / 总风险:低 ## 2. 前置依赖 - 无需补测试(本次全部为纯提取/等价替换,不改变控制流) - #8 需要用户确认业务意图(北京时间 6 点 vs 新加坡时间凌晨 2 点) ## 3. 执行顺序 ### 步骤 1:删除未使用的 QAList struct(#10) - 引用方法:M-L2-02 - 具体操作:删除 `internal/ckwk/types.go` 中 `type QAList struct{}` - 退出信号:`go build ./internal/ckwk/...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 2:修正 typo "以达到" → "已达到"(#9) - 引用方法:M-L2-03 - 具体操作:`internal/ckwk/api.go` 两处 "以达到" 改为 "已达到"(约第 168 行和第 416 行) - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 3:确认 schedule.go 时区意图并修正(#8) - 引用方法:M-L2-03 - 具体操作:注释写"每天 6 点执行",改为 `Asia/Shanghai` + `0 6 * * *` 对齐注释意图 - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证(确认编译通过)+ HUMAN(确认业务意图) - 回滚:git revert ### 步骤 4:提取 userKey 构造为 WK.UserKey() 方法(#4) - 引用方法:M-L2-03 - 具体操作: 1. 在 `internal/ckwk/api.go` 的 `WK` struct 上添加 `func (wk *WK) UserKey() string { return wk.Host + ":" + wk.Username }` 2. 在 `session_manager.go` 中替换 4 处手动拼接为 `wk.UserKey()` 或 `item.Instance.UserKey()` - 退出信号:`go build ./...` 通过 + grep 确认无残留的 `Host + ":" + Username` 拼接 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 5:提取 getWKFromContext 辅助函数(#1) - 引用方法:M-L2-01 - 具体操作: 1. 在 `internal/handler/ckwk.go` 添加 `func getWKFromContext(ctx *gin.Context) (*ckwk.WK, bool)` 2. 替换 5 处重复代码为调用此函数 - 退出信号:`go build ./...` 通过 + grep 确认无残留的 `ctx.Get("wk_instance")` 模式 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 6:提取 retryCode 函数(#2) - 引用方法:M-L2-01 - 具体操作: 1. 在 `internal/ckwk/api.go` 添加 `func retryCode(wk *WK, maxRetries int) (string, error)` 2. 替换 `Login()` 和 `performStudy()` 中的重复重试代码为调用 - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 7:提取 removeSession 内部方法(#3) - 引用方法:M-L2-01 - 具体操作: 1. 在 `SessionManager` 上添加 `func (m *SessionManager) removeSession(sessionID string, item SessionItem)` 2. 替换 `Del()`、`ClearAll()`、`ClearExpired()` 中的重复清理代码 - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 8:SessionManager.Get() 优化锁策略(#5) - 引用方法:M-L4-01 - 具体操作: 1. `Get()` 改为先 RLock 读取,只更新 LastValue 时升级为写锁 2. 由于 Go 的 RWMutex 不支持锁升级,改为:RLock 读 → 检查存在 → RUnlock → Lock 更新 LastValue → Unlock - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 9:GetRecords 递归改迭代(#6) - 引用方法:M-L2-01 - 具体操作:将 `GetRecords` 中的递归分页改为 for 循环,逐页追加到 result.List - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ### 步骤 10:prepareRequestClient 缓存配置(#7) - 引用方法:M-L4-01 - 具体操作: 1. 在 `WK` struct 上缓存上次配置的 debug/proxy/ssl-verify 状态 2. `prepareRequestClient()` 只在配置变化时重建,否则跳过 3. 在 `conf.SetRuntimeDebugEnabled` 被调用后,下次请求时自动触发重建 - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 + HUMAN(切换 debug 开关确认代理/SSL 行为生效) - 回滚:git revert ### 步骤 11:修复 bufferHub.append 切片内存泄漏(#12) - 引用方法:M-L4-01 - 具体操作:在 `h.entries = append(h.entries[1:], entry)` 之前,将 `h.entries[0]` 置为零值 `Entry{}` - 退出信号:`go build ./...` 通过 - 验证责任:AI 自证 - 回滚:git revert ## 4. 风险与看点 - 步骤 8(锁优化):Go RWMutex 不支持锁升级,需 RLock→RUnlock→Lock 两步走,中间可能有竞态导致 LastValue 偶尔不准,但不影响正确性(LastValue 只用于过期清理的时间戳判断) - 步骤 10(配置缓存):需确保 debug 开关切换后首次请求即生效,不能有"延迟一拍"问题