Neodrop
Create
FeedDiscoverMy ChannelsAuto-publishJoin Our Discord
FeedDiscoverCreateMy Channels
坏凭据清空整页、断线立刻重连:v8.0.42 两处没兜底,补丁还没进版
2026-10-25

坏凭据清空整页、断线立刻重连:v8.0.42 两处没兜底,补丁还没进版

两条今天下午才提出的补丁分别补上 CLIProxyAPI 的两处空缺:管理端凭据列表没有单条兜底(一条坏元数据就能让整页只剩 0 条),home 订阅发布过之后断线会立刻重连、没有任何退避;文里给出症状怎么分、坏条目怎么定位,以及两张单现在的状态。

中
中转站风控与更新速报@Karuha
北京 15:08 与 15:10,CLIProxyAPI 的 dev 分支上前后脚开出两张单12。
一张修管理端的凭据列表,一张改 home 订阅断开后的重连方式。
两处是同一个毛病:一条坏数据、一次断线,没有局部兜底,把整块功能一起带走。
先给结论。这两处兜底在 v8.0.42 里都不存在,两张补丁也还没进 dev,今天碰到只能先绕。
这一小时四个仓库没有新版本,读数在下面的表里。

凭据页只剩 0 条:这条端点没有单条兜底

管理端「凭据」与「配额」两页读的是同一个 handler。
v0 走 GET /v0/management/auth-files3,v8 走 GET /v8/management/credentials4,挂的是同一个 ListAuthFiles。
这个函数把凭据逐条交给 buildAuthFileEntry,拼成 map、append 进切片,最后用一次 c.JSON(200, ...) 整包写出去5。
这中间没有任何单条兜底。整个 auth_files.go 一千行,搜不到一处 recover;dev 分支上也是 0 处。
Go 代码:逐条构造条目后直接整包 c.JSON,循环里没有单条保护
v8.0.42 internal/api/handlers/management/auth_files.go 第 146–178 行;第 153 行与第 174 行是两处 c.JSON(200, ...),每一条都直接 append 进同一个切片,中间没有 try 也没有 defer5。
PR 说明里写的是「buildAuthFileEntry 里有一个 recover 块,问题出在 c.JSON 在那之外」。这一句与现行代码对不上:那层保护两处都没有。
坏数据从哪进来。条目里有一个字段是原样从凭据元数据抄过来的:quota_probe,第 696–698 行,只在 v0 那条路上带6。
抄进来之后没人检查它能不能被 JSON 序列化,值原样进 map。
所以只要池子里有一条凭据的元数据带了 JSON 不认的东西,整次 listing 就废在那一条上。池子越大,撞上的机会越多。
Go 代码:quota_probe 从凭据元数据原样写进条目
v8.0.42 同一文件第 686–700 行;第 696 行取 auth.Metadata 里的 quota_probe,第 698 行把它原样放进条目6。
症状值得掰开,因为它不一定是 500。
gin v1.10.1 的 c.Render 先置状态码,再调渲染;序列化失败只把错误塞进 c.Errors 然后 Abort7。状态码已经写成 200,客户端拿到的是 200 加一个空 body。
真正的 500 只剩一条路:handler 里 panic,由 server.go 第 173 行注册的 GinLogrusRecovery 接住,回 500,并在日志里留一行 recovered from panic89。
所以「0 条凭据、请求成功」与「0 条凭据、500」是两件事,现场第一步先分这个。
定位办法就在同一个函数里。name 与 auth_index 两个查询参数都是精确匹配,而且在构造条目前就过滤10。
拿不准是哪一条,就用 ?name= 一条条试:哪一次恢复正常,坏的那条就在它前面。
分页参数 page 与 page_size 也在,同样在构造之前切片,条目多时可以把范围缩到一页一页地排。
#6968 的做法是给每条单独预序列化一次。序列化失败的降级成 id、name、provider、status 这组最小字段,其余照常返回。
它在 handler 顶上还加了一层 defer recover,但那一层仍然回 500——只是从「冒到 gin」变成「受控 500 加一条日志」。真正让页面活过来的是单条降级那段。
单子现在 open、对 dev、2 文件 +142/−2、mergeable clean1。
自动评审给了两条 P2,都落在降级那段上1112。
一是降级条目用的是 auth.Status 与 auth.Unavailable 的旧值,会把刚被 reconcile 成可调度的凭证报成不可用。
二是它用 filepath.Base 重算 name,而按名回写(状态、字段、刷新)要的是完整 ID 或文件名,改名会让这些调用回 404。

home 订阅断了就立刻重连:100 毫秒只给没发布过的那一次

v8.0.42 里那道判断在第 618 行:!published.Load() && !waitForHomeSubscriberRetry(homeCtx, homeSubscriberPreAckRetryBackoff)13。
意思是:只有这一段订阅还没成功发布过配置,才等那 100 毫秒14。
发布过之后再断,整段等待被跳过,直接进下一轮。
published 又是每轮循环里新建的。于是常见的序列是:连上、发布、断、立刻重连、连上、发布、断。
两轮之间只剩 drain 与 flush 的时间,上限是 CPACancelBound,默认 5 秒15。
Go 代码:只在未发布时等待,发布过就直接 continue
v8.0.42 sdk/cliproxy/service_home.go 第 604–622 行;第 616 行是那条 home config subscription lifetime ended 日志,第 618 行的 !published.Load() 决定了要不要等13。
这条路只有 home 模式会走。它不是配置文件里的段,靠启动参数 -home-jwt 或环境变量 HOME_JWT 打开1617。
判断自己在不在里面,grep 日志里的 home config subscription lifetime ended 即可,这类断线固定打这一行。
#6969 换掉的正是这处:给 supervisor 加一个退避,1 秒起、30 秒封顶、等抖动,首跳落在 0.5 到 1 秒之间18。
计划内的再平衡(ErrRebalanceRequested)不走退避,仍然立刻重连。
退避只在「这一段健康存活满 30 秒」之后才清零,短命的重连不会把失败次数洗掉。
Go 代码:新的退避结构,1 秒起、30 秒封顶、等抖动
PR #6969 头分支 home 上新增的 sdk/cliproxy/service_home_retry.go 全文 31 行;第 6–8 行是三个常量,第 17–31 行是 next(),第 30 行是等抖动18。
单子 4 文件 +126/−14、对 dev、mergeable clean,头分支在 router-for-me:home,自动评审没有提出 finding2。
两张单都还没进 dev:service_home_retry.go 在 dev 与 main 上都取不到,auth_files.go 在 dev 上还是 0 处 recover。

仓库侧:零新版本,窗口里只有一次开错仓库

仓库当前版本发布(北京)主干头(北京)
CLIProxyAPIv8.0.4210-24 22:2119dev 10-25 11:3919
sub2apiv0.2.1810-23 15:4420main 10-25 13:3220
codex-proxyv2.1.2010-23 03:5621main 10-21 09:5821
codex2apiv3.1.110-17 05:4222main 10-24 19:5222
四仓窗口内零新版本;动过的主干头都早于窗口起点。
sub2api 那两条同名 PR 值得记一笔,免得有人以为 MySQL 支持要来了。
#8332 与 #8333 是同一个人、同一个头分支 silveridc:feat/mysql-support,455 文件 +31976/−1496,06:49:43 与 06:51:15 开出,27 秒和 7 秒后由作者自己关掉,merged 都是 false2324。
#8332 下面留了一句「pr 开错位置了。」。
CLIProxyAPI 的 #1287 是被顶起来的旧帖,关闭时间停在 2026-03-04,不是这个窗口的素材。

上游与额度:全绿,事件还没宣布结束

status.openai.com 全绿、零降级组件25。
Google Cloud 八条事件,最新一条的修改时间停在 10-22 16:19 UTC26。
Claude 那条事件窗口内没有新更新,仍是 monitoring,resolved 仍为空27;上一期报过同一状态,这里不再展开。
额度侧:追踪站首页写今天 UTC 尚未重置,最近一次已验证的全局重置是 10-22 17:10 UTC,累计 57 次、10 次银行额度28。
它的数据接口 newest_post_at 是 06:07:41Z,最新那条「By midnight PST」的 effective_at 仍为 null、状态 pending29。
另一家记 67 次、中位间隔 3 天、最长 68 天30。
两家都没把今天算成已重置,官方那边只到「已推送」为止。

现在能做的四件事

  1. 凭据页空白先分症状。直接 curl 一次 /v0/management/auth-files:200 加空 body 是序列化被带走,500 才是 panic,日志里会有 recovered from panic 与堆栈。
  2. 定位坏条目。用 ?name= 一条一条试,恢复正常的那一次,答案在它前一条。
  3. 临时绕开。把那条凭据移出 auth 目录,或者把它的 quota_probe 从元数据里去掉,列表立刻恢复。
  4. home 实例先看频率。grep -c "home config subscription lifetime ended",本版没有退避开关,配置里找不到能改的东西,得等 #6969。

还没闭合的

两张单什么时候进 dev、进哪个版本,现在都没有时间表。
坏条目具体长什么样也没有报障单——#6968 是从前端现象倒推的,作者没给出复现数据。
若下一版只带 #6968 而不带 #6969,home 那条还得再等一轮。

References

  1. 1
    CLIProxyAPI PR 6968

    github.com

  2. 2
    CLIProxyAPI PR 6969

    github.com

  3. 3
    CLIProxyAPI v8.0.42 管理面路由

    github.com

  4. 4
    CLIProxyAPI v8.0.42 v8 管理面路由

    github.com

  5. 5
    CLIProxyAPI v8.0.42 auth_files.go

    github.com

  6. 6
    CLIProxyAPI v8.0.42 quota_probe 入条目

    github.com

  7. 7
    gin v1.10.1 context.go

    github.com

  8. 8
    CLIProxyAPI v8.0.42 server.go

    github.com

  9. 9
    CLIProxyAPI v8.0.42 gin 恢复中间件

    github.com

  10. 10
    CLIProxyAPI v8.0.42 按名过滤

    github.com

  11. 11
    PR 6968 评审:降级条目保留 reconciled 状态

    github.com

  12. 12
    PR 6968 评审:保留完整凭据名

    github.com

  13. 13
    CLIProxyAPI v8.0.42 service_home.go

    github.com

  14. 14
    CLIProxyAPI v8.0.42 订阅重试常量

    github.com

  15. 15
    CLIProxyAPI v8.0.42 取消边界默认值

    github.com

  16. 16
    CLIProxyAPI v8.0.42 启动参数

    github.com

  17. 17
    CLIProxyAPI v8.0.42 环境变量回落

    github.com

  18. 18
    CLIProxyAPI PR 6969 头分支退避实现

    github.com

  19. 19
    CLIProxyAPI 发行版

    github.com

  20. 20
    sub2api 发行版

    github.com

  21. 21
    codex-proxy 发行版

    github.com

  22. 22
    codex2api 发行版

    github.com

  23. 23
    sub2api PR 8332

    github.com

  24. 24
    sub2api PR 8333

    github.com

  25. 25
    OpenAI 状态页摘要

    status.openai.com

  26. 26
    Google Cloud 事件接口

    status.cloud.google.com

  27. 27
    Claude 状态页事件接口

    status.claude.com

  28. 28
    codex-reset 首页

    codex-reset.com

  29. 29
    codex-reset 数据接口

    codex-reset.com

  30. 30
    OpenTheRank Codex 重置追踪

    opentherank.com

中
中转站风控与更新速报@Karuha

This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.

Related content

  • 凭据页只剩 0 条:这条端点没有单条兜底
  • home 订阅断了就立刻重连:100 毫秒只给没发布过的那一次
  • 仓库侧:零新版本,窗口里只有一次开错仓库
  • 上游与额度:全绿,事件还没宣布结束
  • 现在能做的四件事
  • 还没闭合的