mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
fix(quota): hostOf 用了 gmatch 而不是 match —— memo 表从未命中过任何东西
## 这是退避失效的真正原因,而且比 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。
This commit is contained in:
@ -63,8 +63,23 @@ end
|
||||
-- hostOf extracts the host from a base_url, for showing WHICH upstream a row is
|
||||
-- about. Two sources on the same vendor (two Command Code keys) are
|
||||
-- indistinguishable without it.
|
||||
-- hostOf returns the host of a URL — the part memoisation is keyed on, so two
|
||||
-- sources pointing at the same host with different paths share one answer.
|
||||
--
|
||||
-- It used to be written with string.gmatch and a capture group. gmatch yields
|
||||
-- WHOLE matches, not captures, and with `^` it never advances, so the iterator
|
||||
-- returned nil on the first step and hostOf returned its `or u` fallback —
|
||||
-- the FULL URL.
|
||||
--
|
||||
-- The consequence was invisible and total. Every lookup was HOST_MEMO[nil] and
|
||||
-- every write was HOST_MEMO[nil], so:
|
||||
-- - the memo table never returned anything, for any host, ever
|
||||
-- - the negative memo, the TTL and (later) the backoff were all dead code
|
||||
-- - the 19 entries in this gateway's production state are unreachable: their
|
||||
-- keys are full URLs, while a lookup asks for nil
|
||||
-- Measured before the fix: hostOf(key) matched 0 of 19 production entries.
|
||||
local function hostOf(u)
|
||||
return (string.gmatch(u, "^https?://([^/]+)")()) or u
|
||||
return (string.match(u, "^https?://([^/]+)")) or u
|
||||
end
|
||||
|
||||
-- get walks a dotted path through nested tables, returning nil if any hop is
|
||||
|
||||
Reference in New Issue
Block a user