Skip to content

fix: 隔离登录成功却丢凭据 —— Close 超时污染返回值 - #66

Merged
Mag1cFall merged 3 commits into
Mag1cFall:mainfrom
swdswd2401999-ops:fix/login-close-loses-credentials
Oct 19, 2026
Merged

Mag1cFall merged 3 commits into
Mag1cFall:mainfrom
swdswd2401999-ops:fix/login-close-loses-credentials

Conversation

@swdswd2401999-ops

Copy link
Copy Markdown

问题

setup --login --remote <origin> 走完登录、进入 AI Studio、窗口自动关闭,最后报:

等待 Camoufox 进程退出: context deadline exceeded

而服务器上账号列表没变、auth/ 目录里账号文件的时间戳也没变 —— 凭据白抓了一次。

同一个 Google 账号每次都要重新登一遍。

根因:三层叠加

1. Close() 的错误污染了返回值

internal/camoufoxnative/login.go:

defer func() {
    err = errors.Join(err, session.Close())
}()

登录状态在上面 session.exportStorageState() 就已经拿到并编码完了,只是 defer 里 Close() 报错,就让整个 Login() 返回错误。

2. 调用方无条件删除临时目录

internal/setup/setup.go:

defer os.RemoveAll(loginDirectory)

第 1 点让 Login() 失败,调用方立刻返回,defer 把刚抓到 storage-state 的目录删掉。指纹文件一起没。

3. 关闭超时只有 5 秒

const browserProcessCloseTimeout = 5 * time.Second

Windows 上关浏览器走 taskkill /PID x /T /F,要结束整棵进程树。Camoufox 900MB 级,正常要落盘 profile、回收 6-9 个渲染进程,实测经常超过 5 秒。

一个反直觉的观察

同一台机器、同一个账号、同一个流程,早上两次成功,下午连续失败。差别只在机器状态:

早上   camoufox 进程数 1     →  taskkill 一次完成,5 秒够
下午   camoufox 进程数 9     →  要杀 9 个进程树,5 秒必然不够

而这 9 个进程正是前两次失败残留的。于是形成恶性循环:失败→残留→更容易超时→更多残留。

只改代码不清理现场,仍然会反复失败。

修复

login.go —— Close 失败只警告,不改变返回值:

defer func() {
    if closeErr := session.Close(); closeErr != nil && err == nil {
        fmt.Fprintf(os.Stderr, "警告: 关闭 Camoufox 失败(不影响登录结果): %v\n", closeErr)
    }
}()

关闭失败只说明进程回收不干净,与登录结果无关 —— 状态早已拿到。

launcher.go —— 关闭超时 5s → 20s,覆盖正常关闭;真正的僵死进程仍会被截断。

setup.go —— 只在成功时删临时目录;失败时保留并打印路径:

保存账户失败,临时目录已保留: /tmp/aistudio2api-login-12345

用户可以手工导入,不用重登:

aistudio2api setup --storage-state /tmp/aistudio2api-login-12345/storage-state.json

实测

修复后同一次登录,Close 依然超时,但流程走完了:

警告: 关闭 Camoufox 失败(不影响登录结果): 等待 Camoufox 进程退出: context deadline exceeded
账户已保存: swd2279807962@gmail.com

服务器 /api/accounts 立即出现该账号,state=ready,origins=2,42 cookies,直连。

$ go vet ./internal/camoufoxnative/ ./internal/setup/    (无输出)
$ go test ./internal/setup/ ./internal/camoufoxnative/
ok  internal/setup          5.904s
ok  internal/camoufoxnative 0.224s

影响面

只影响隔离登录流程(setup --login)。不影响运行时、不影响已存在的账号、不影响 Chrome 导入路径。

如果能合并,建议同时提醒用户:连续失败时先清理残留的 camoufox 进程再重试,否则即使有这个修复,日志里还是会刷关闭警告。

LCS added 2 commits October 19, 2026 19:33
zeroQuotaLimit() 已把这类 429 标成「无配额」,说明代码识别出它不是
额度用完而是账号没有该模型的访问权限。但 until 仍取自 RetryDelay,
于是每次都是:冷却 19 小时 → 到点重试 → 又是 limit: 0 → 再等 19 小时。

实测依据:
- 9/9 条 retry in 精确指向 UTC 零点(如 04:49:51 + 19h10m8s = 次日 00:00:00)
- 次日同一模型同一账号仍是 limit: 0,等多久都不恢复
- 只有 4%(7/156)的 argon 请求受影响,因为系统会自动回退 playground

改为走已有的 planLimitBackoff(1m → 5m → 15m → 30m → 1h):
- 权限若真开通,一小时内就能发现,而不是等 19 小时
- 若没开通,代价是每小时一次失败探测(约 60ms,不占并发槽)
- 复用 planLimitCooldown 的 Level 递增逻辑,不改动其他分支

测试:internal/aistudio/quota_zerolimit_test.go 覆盖 8 种情形
(limit:0 / limit:100 / 混合 / 无 limit 字段 / 递增 / 封顶 / 冷却未过期 / global 标记)
症状:setup --login --remote 走完登录、进入 AI Studio、窗口自动关闭,
最后报「等待 Camoufox 进程退出: context deadline exceeded」,
而 auth 目录里账号文件时间戳没变,凭据白抓一次。

三层原因叠加:

1. login.go 把 Close 的错误 errors.Join 进返回值
     defer func() { err = errors.Join(err, session.Close()) }()
   状态在上面的 exportStorageState 已经拿到并编码完毕,
   但 Close 失败让整个 Login() 返回错误。

2. setup.go 无条件删除临时目录
     defer os.RemoveAll(loginDirectory)
   于是调用方在推送之前就把刚抓到的 storage-state 删了。

3. browserProcessCloseTimeout 只有 5 秒
   Camoufox 是 900MB 级浏览器,要落盘 profile、回收 6-9 个渲染进程,
   taskkill /T /F 经常超过 5 秒。进程越多越慢 —— 失败残留的进程
   累积后形成恶性循环,越试越容易超时。

实测:同一台机器早上两次登录成功(进程干净),下午连续失败
(9 个 camoufox 残留)。差别只在机器状态。

修复:
- Close 失败只写 stderr 警告,不改返回值
- 关闭超时 5s -> 20s,覆盖正常关闭,僵死进程仍会被截断
- setup 失败时保留临时目录并打印路径,可手工导入:
  aistudio2api setup --storage-state <路径>/storage-state.json

2026-10-19
@Mag1cFall

Copy link
Copy Markdown
Owner

Hi,我读完了改动,在合入前我会新增一个commit在这里

本项目大体遵守的是三点:

  • 客户端需要的,我们就兼容,不主动拒绝
  • fail-fast
  • 对于默认行为,优先尊重可用性,其次尊重上游(比如user轮续写)

这个改动照顾的情况参杂了太多假设,我认为加入手动清理限额的动作要比退避重试好,不论如何我们没有理由猜测上游的权限变化,也不需要猜测
同时这里的测试应无用,这个实现不需要以这种方式锁住
对于上游可用性问题,没有客户端要求猜测的情况下,按照项目思想,应选择尊重上游

Camoufox的改动类似,这个问题是存在的 但是代码改动我会再修一下

@Mag1cFall
Mag1cFall force-pushed the fix/login-close-loses-credentials branch from 1642422 to fe1b599 Compare October 19, 2026 16:40
- 导出认证状态后关闭 Camoufox 失败时仍保存账户,setup 输出与管理端请求日志报告关闭失败原因
- Windows 上每个 Camoufox 归入独立 Job,关闭时结束含父进程已退出在内的全部子孙进程后删除 profile
- 冷却列表返回作用键,管理端冷却详情可手动清除模型、Build 与账户级冷却
- 额度冷却按上游 RetryDelay 计时,账户限额由管理端手动清除冷却处理
- 关闭 Camoufox 最多等待 5 秒,setup 结束时总是删除临时登录目录
@Mag1cFall
Mag1cFall force-pushed the fix/login-close-loses-credentials branch from fe1b599 to dda8fee Compare October 19, 2026 16:57
@Mag1cFall
Mag1cFall merged commit 00ad27b into Mag1cFall:main Oct 19, 2026
3 checks passed
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.

2 participants