Skip to content

fix(upstream): 同账号 refresh 单飞,避免 RT 复用撞 12153 掉登录 (#215) - #217

Merged
linguo2625469 merged 1 commit into
linguo2625469:mainfrom
louddong:main
Oct 21, 2026
Merged

linguo2625469 merged 1 commit into
linguo2625469:mainfrom
louddong:main

Conversation

@louddong

Copy link
Copy Markdown
Contributor

上游对 refreshToken 反重放:同一 RT 被消费后再用会返回 12153 并整条 RT 链 作废,账号从此恒 401、只能人工重新登录。而 scheduler keepalive、handler 临近 过期刷新、signin 工具都会并发触发同一账号的 refresh(原实现把 I/O 放在锁外,
a.mu 挡不住并发),于是掉登录概率随并发升高。

  • RefreshToken 按 UID 做 single-flight:并发调用等待并复用首个结果,不重复打 上游;不同账号仍并行,不拖慢 keepalive 全量刷新。
  • 12153 兜底:磁盘 auth 文件已被其他进程(server + signin 双进程部署)rotate 过时,采纳磁盘 token 重试一次,跨进程竞态也能自救。
  • 新增用例:并发单飞、按账号隔离、磁盘 token 采纳、无变化不重试; go test -race ./internal/upstream 通过。

上游对 refreshToken 反重放:同一 RT 被消费后再用会返回 12153 并整条 RT 链
作废,账号从此恒 401、只能人工重新登录。而 scheduler keepalive、handler 临近
过期刷新、signin 工具都会并发触发同一账号的 refresh(原实现把 I/O 放在锁外,
a.mu 挡不住并发),于是掉登录概率随并发升高。

- RefreshToken 按 UID 做 single-flight:并发调用等待并复用首个结果,不重复打
  上游;不同账号仍并行,不拖慢 keepalive 全量刷新。
- 12153 兜底:磁盘 auth 文件已被其他进程(server + signin 双进程部署)rotate
  过时,采纳磁盘 token 重试一次,跨进程竞态也能自救。
- 新增用例:并发单飞、按账号隔离、磁盘 token 采纳、无变化不重试;
  go test -race ./internal/upstream 通过。
@ywnd1144

Copy link
Copy Markdown

问题已经解决了,上游自动恢复了被强制下线的会话,所有账户无需重新登录,重新刷新就恢复了

Smirk1921 added a commit to Smirk1921/workbuddy2api-panel that referenced this pull request Oct 18, 2026
…153 掉登录

上游 linguo2625469#217(作者 louddong,对应 issue linguo2625469#215)。
本补丁的基线 blob 与我们的 6b31db6 完全一致,`git apply --check` 通过,无手工改动。

问题:上游对 refreshToken 有反重放——同一 RT 被消费后再用会返回 12153 且整条 RT 链
作废,账号从此恒 401、只能人工重新登录。而 scheduler keepalive、handler 临近过期刷新、
signin 工具都会并发触发同一账号的 refresh;原实现把网络 I/O 放在锁外,a.mu 只挡住写回,
挡不住**两次消费同一个 RT**。写回前的快照校验只防止了写竞争,没防止重复消费。

改动(internal/upstream/client.go +93/-6):
- Client 新增 refreshMu / refreshInFlight,按 a.UID 做 single-flight 票据
  (sync.Mutex + map[string]*refreshFlight + 每 key 一个 done channel);
  leader 独占打上游,follower 阻塞 <-done 后直接复用结果;
- 原两段式刷新逻辑原样搬进 refreshTokenOnce(行为不变);
- 12153 兜底:读磁盘 auth 文件,若 RT 已被别的进程 rotate 过则采纳并**只重试一次**
  (server + signin 双进程部署的跨进程竞态自救);磁盘未变则保持失败语义;
- 新增 refresh_singleflight_test.go(4 个用例:同账号单飞 hits==1/maxInFlight==1、
  按账号隔离 maxInFlight>=2、12153 后采纳磁盘新 RT 重试、磁盘未变不重试)。

验证:go build ./... 通过;go test ./... 全绿;4 个新用例全过。
(`-race` 在本机跑不了:没有 C 编译器,项目一贯 CGO_ENABLED=0。单飞用例用
hits==1 / maxInFlight==1 的确定性断言覆盖了同一竞态。)

已知边界(本补丁不解决,仅记录):
- 跨进程仍是尽力而为:失败方读磁盘时若赢家尚未 SaveAtomic,磁盘还是旧 RT,仍会被判
  12153。TOCTOU 无法靠进程内单飞消除。
- close(done) 到 delete(map) 之间新来的调用会命中已完成票据,直接拿到旧结果。
- UID 为空的 auth 退化为按对象指针做 key,只保证同一对象串行。
Smirk1921 added a commit to Smirk1921/workbuddy2api-panel that referenced this pull request Oct 18, 2026
- README:新增「账号批量操作升级」「任务节奏可配置」「仪表盘 + 积分口径开关」
  三节,并附上摘取的上游 PR linguo2625469#217 与「国际版签到不需要实现」的实测结论
  (含复现工具),避免以后重复调研。
- 仪表盘第一张 KPI(可用积分)在 6 列布局下 23px 字号装不下「剩余 / 总额」两个数,
  会被卡片 overflow 裁掉:加 .kpi.kpi-sm(17px)并把标签精简为「可用积分」,
  口径移到底部说明(排除冻结/暂停 · 全部 X / Y)。实测 1280/1100 单行、
  900/760 两行,四个宽度均无横向溢出。
jin66god pushed a commit to jin66god/workbuddy2api-panel that referenced this pull request Oct 18, 2026
jin66god pushed a commit to jin66god/workbuddy2api-panel that referenced this pull request Oct 18, 2026
jin66god added a commit to jin66god/workbuddy2api-panel that referenced this pull request Oct 19, 2026
jin66god added a commit to jin66god/workbuddy2api-panel that referenced this pull request Oct 19, 2026
pardSun added a commit to pardSun/workbuddy2api-panel that referenced this pull request Oct 20, 2026
shinny-xionghongwei added a commit to shinny-xionghongwei/workbuddy2api-panel that referenced this pull request Oct 20, 2026
WilliamLuuu added a commit to WilliamLuuu/workbuddy2api-panel that referenced this pull request Oct 20, 2026
@linguo2625469
linguo2625469 merged commit 3dc964d into linguo2625469:main Oct 21, 2026
maintell added a commit to maintell/workbuddy2api-panel that referenced this pull request Oct 21, 2026
吸收的上游修复(均为 bug fix):
- linguo2625469#233 国际版 11-128 通道校验分流 + 始终发送 X-Conversation-ID(取代本地 linguo2625469#190 旧实现;11-128 不再硬禁用账号)
- linguo2625469#159 剥离 content 里的 reasoning_text 片段,修 Codex 转换后 11101
- linguo2625469#185 6021 queue.full 归为渠道级繁忙(不轮转、不罚号,503 upstream_busy)
- linguo2625469#217 同账号 refresh 单飞,避免 RT 复用撞 12153 掉登录
- linguo2625469#162 识别企业切换会话 token_source=enterprise_switch
- linguo2625469#199 缓存告警假阳性:miss 显式存在时对称反推 hit
另含 linguo2625469#138 linguo2625469#143 linguo2625469#144 linguo2625469#158 linguo2625469#178 linguo2625469#196 linguo2625469#205 linguo2625469#213 linguo2625469#220 linguo2625469#221 linguo2625469#223 linguo2625469#225 linguo2625469#230 linguo2625469#232 等功能更新。
本地改动:README 停维护声明改写为本 fork 口径;版本号 1.14.0-panel。
qcgzxw added a commit to qcgzxw/workbuddy2api-panel that referenced this pull request Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants