mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
## 这是退避失效的真正原因,而且比 TTL 严重
查生产 state 时发现的:19 条 memo,`hostOf(key)` 命中 **0** 条。
hostOf = function(u)
return (string.gmatch(u, "^https?://([^/]+)")()) or u
end
`string.gmatch` 返回**整个匹配**,不是捕获组;而带 `^` 锚定时迭代器不会前进,
所以第一次 `()` 调用返回 **nil**,函数走 `or u` 分支返回完整 URL。
后果是彻底的、而且完全静默:
- 每次查表都是 HOST_MEMO[nil],每次写入也是 HOST_MEMO[nil]
- memo 表**对任何 host 从未命中过**
- 负 memo、PROBE_MEMO_TTL、以及刚加的指数退避,**全是看起来活着的死代码**
- 生产那 19 条历史 memo(key 是完整 URL,来自 ccquota 时代)从来没有被读过
所以「两个死上游每 30 分钟重付一次探测」的真实原因不是 TTL 到期,
而是压根没命中过 memo。
## 为什么这么久没人发现
失败模式与「memo 里没有可记的东西」完全不可区分:页面照常显示,卡片照常
skipped,没有任何报错。唯一线索是 state 里那 19 条条目 —— 它们看起来像是
在正常工作留下的痕迹。
## 修法
string.match(u, "^https?://([^/]+)")
判据 `TestQuotaMemoKeyIsTheHost` 钉住它:读**实际发布的** quota.lua,检查
用 string.match,并在运行时验四个 URL 的 host 抽取,以及同一 host 的两个不同
路径必须产出同一个 key(这正是按 host 做 memo 的意义)。
变异把 match 改回 gmatch 立刻变红,并打印出实际返回的完整 URL。