- 提取 getWKFromContext 辅助函数,消除 handler 中 5 处重复代码 - 提取 retryCode 函数,消除 Login/performStudy 中验证码重试重复 - 提取 removeSession 内部方法,消除 Del/ClearAll/ClearExpired 中 3 处重复 - 提取 WK.UserKey() 方法,消除 4 处 userKey 手动拼接 - SessionManager.Get() 改用 RLock 优化读性能 - GetRecords 递归分页改为迭代,避免栈溢出 - prepareRequestClient 添加配置缓存,仅在 debug 设置变化时重建 - 修正 schedule.go 时区为 Asia/Shanghai + cron "0 6 * * *" - 修正 typo "以达到" → "已达到" - 删除未使用的 QAList struct - 修复 bufferHub.append 切片内存泄漏 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
129 lines
5.1 KiB
Markdown
129 lines
5.1 KiB
Markdown
---
|
||
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 开关切换后首次请求即生效,不能有"延迟一拍"问题
|