Skip to content

v3.10.5

Choose a tag to compare

@github-actions github-actions released this 07 Nov 07:38
· 31 commits to master since this release

v3.10.5

v3.10.5 — 状态机原子性:并发冷却、Key 分类、软超时副作用

PR #29。本次不发 MCP Registry。

变更

  • MMR 的 target_count 缺省值改为跟随 max_size:smartsearch.mmr.target_count: 0(缺省)此前表示「对全部结果做重排」,而超出 max_size 的尾部随后必被截断丢弃,等于白做一轮二次方贪心选择。现在缺省取 max_size 为上限,max_size 不限时仍重排全部(旧语义);显式配置 target_count 的行为不变。MMR 贪心选择具有前缀性(选前 k 项与对全量选择后的前 k 项相同),输出内容不变,只省掉无用工作
  • URL 归一化统一为一套语义:评分增强的跨引擎去重键(enhance.normalizeURLKey)改为委托 core.NormalizeURL,与去重主链路一致——现在同样剥离 utm_*/fbclid/gclid/ref/spm 追踪参数并排序查询参数。行为收紧点:跨 scheme / www. 的变体不再合并(与 core 键一致)

修复

  • 并发状态迁移的原子性(P0):会话轮换、冷却档位升级、成功清理三处状态迁移此前跨锁边界「读出来-判断-写回」,并发搜索下可复现真实竞争。现在轮换(计数 + 判定 + client/UA 重写)整体入锁、请求取用同一临界区的会话快照;冷却档位计算收敛为纯函数 antirobot.NextCooldownDuration,读写在同一临界区完成;成功路径引入状态代次快照,只在「本次请求期间没有并发请求进入冷却或记录失败」时才清理对应状态。ddg/baidu/bing/google/so360/arxiv 六处受影响
  • 传输层瞬断不再冻结 API Key 30 分钟(P0):KeyError 此前同时表达「key 坏了」与「这次调用失败了」,apipool 只要命中就 MarkInvalid 30 分钟——单 Key 供应商一次网络抖动即 30 分钟不可用。现在 KeyError 带显式分类(auth / rate_limit / transport / content),apipool 按分类查表:鉴权失败冷却该 key,限流短冷却(5 分钟),传输层与内容类失败不冷却任何 key 且立即级联下一供应商
  • 全部 Key 失效时不再下发已知失效的 Key:KeyPool.Next() 在池内全部冷却时返回空串,新增 NextUsable() 返回是否取到;8 个供应商与 mcphub 均改为「取不到即上报明确错误」,不再拿着已被冷却的 key 去打一次必然被拒的请求
  • 删除并发下会标错 key 的 MarkLastInvalid:该方法标记的是「池级最近返回的 key」而非「本请求实际使用的 key」,并发下会误冻好 key、放过坏 key(代码注释早已自认非并发安全)。已整体删除,兜底路径改为按 KeyError 分类处理
  • 软超时放弃后不再改状态(P1):编排层对超时引擎放弃等待后,引擎的 goroutine 仍继续推进冷却与会话状态,导致观测层记「超时失败」而上游记「成功」。新增 antirobot.ContextEngine 可选接口(ddg/baidu/bing/google/so360/arxiv/github 实现),ctx 取消后请求立即中止,且被放弃的调用不再推进冷却 / 会话轮换 / 退避状态;前置退避等待也改为可被 ctx 取消
  • 重复 stop 不再重复触发关闭(P1):refcount 的「检查 + 更新」改为锁内完成并按饱和处理,只有真正的 1 → 0 迁移才发关闭信号——此前计数已为 0 时再 -1(脚本重试、客户端重复 stop)会每次都重发一次关闭信号
  • academicsearch 分页不再静默退化(P1):缓存键此前不含 page,page≥2 在 TTL 内会命中第一页的记录并返回第一页结果。现在页码参与缓存键
  • 缓存代次写入的静默丢弃变为显式报告:Clear() 与在飞写入并发时,旧代次视图的写入按设计作废,此前静默返回 nil;现在返回哨兵 cache.ErrStaleGeneration,mcp 调用方按竞态静默处理,其它写入错误记日志
  • mcphub 空结果按失败同待遇冷却:后端返回 200 但零结果(或抓取空正文)此前记进失败清单却不触发冷却,语义不对称且持续重试浪费上游配额;现在以哨兵 mcphub.ErrEmptyResults 判定并参与冷却(不靠错误文本关键词匹配)
  • 本端限流的归因不再失真:baidu / bing / google / github / googlenews / wikipedia / so360 七个引擎在本端限流器拒绝放行时返回「空结果 + nil error」,被编排层记成「成功但零结果」——失败清单为空、聚合错误变成「所有搜索引擎均未返回有效结果」,控制中心的失败构成里完全看不到限流这一类。现在统一返回哨兵 antirobot.ErrLocalRateLimit,失败清单正确产出 kind=rate_limit
  • 评分流水线热点:分词去正则:tokenize 是评分流水线的 CPU 与分配热点(正则 FindAllString 的匹配状态机开销高),改为手写字节扫描,语义逐字节等价(等价性用例以旧正则实现为 oracle 覆盖中英混排、CJK 长串、emoji、ASCII 边界等语料)
  • 独立评审补缺口(合入前):baidu / bing / google / so360 / arxiv / github 补齐 SearchContext(ctx 取消后不再改退避 / 冷却 / 会话);KeyPool.MarkInvalidFor 取较长截止,并发短冷却不再覆盖鉴权长冷却;DDG 本端限流改走 LocalLimitSkipped;academicsearch 省略 page 与 page=1 共用缓存键;TinyFish / Keenable 的 429/403 按 keyErrorKindByStatus 分类;NewKeyError 零 Kind 强制写成 transport