Skip to content

v12

Choose a tag to compare

@NeonMedusa NeonMedusa released this 07 Oct 02:22
· 5 commits to main since this release
fix(stream): 空闲看门狗治半开连接卡死(全路径覆盖)+ 压缩重试 + 缓存 0% 显示

背景:TCP 半开(服务端不发也不关)时阻塞读永久挂住,生产实测会话卡死
92 分钟无恢复;截断检测/重试/Ctrl+Q 全部无法触发(Zig http.Client 只有
连接超时,无流式读超时)。

## 空闲看门狗(netShutdown 唤醒阻塞读)
- ai.zig 新增 watch_slot(句柄/打点/唤醒标记/互斥,宿主注入):
  streamMessage 与 listModels 连接建立/重定向后发布 socket 句柄,
  读循环每块数据打点(首字节前等待也计入)
- 唤醒用 netShutdown(.both):Windows AFD 的 receive-only 断开不完成
  挂起的读(实验实测 .recv 挂起 47s+ 无效、.both 毫秒级唤醒)
- 读失败归类:取消优先 → 看门狗唤醒按截断(可重试)→ 否则网络错误
- 发布/清除在锁内且先于连接关闭(defer 顺序),杜绝句柄复用误伤

## 覆盖路径(阈值 stream_idle_timeout_ms,默认 180s,测试可注入)
- 流式主请求:主循环每帧 + CLI ask 循环每轮泵
- 手动 /compact(异步):主循环泵(守卫扩到 isCompacting)
- 工具轮中途压缩:主循环泵(守卫扩到 compact_live_running)
- 同步压缩(阻塞主线程):runCompaction 临时起专用看门狗线程
- 模型列表拉取:独立槽位(菜单可在生成/压缩中打开,与流式并存)+ 专用线程
- Ctrl+Q:卡死时立即唤醒(此前完全无效);压缩取消同样生效

## 压缩流重试(与主流同策略)
- 手动/中途/同步三条路径均可重试网络错误/截断/瞬时故障;上限 3 次
  (stream_retry_max 2→3,同步主流),指数退避 + 抖动
- 重试前握手:请主线程丢弃失败尝试的气泡与缓冲并回 ack(10s 兜底自清)
- 压缩失败且无气泡时补一行失败提示(此前静默无提示);
  finalizeCompaction 补 drain(末段增量不丢)

## 状态栏:cached=0 显示完整段(方案 B)
- 此前 cached=0 时 "缓存 X/Y" 段被隐藏,命中率与前段粘连为 "think:max0%"
- 现在统一为 " · 缓存 0/141.5k 0%",与命中态格式一致(纯服务端真实值)

## 顺带修复两处潜伏 bug(此前 mock 未启动、相关测试处于 skip 未暴露)
- createStreamJob:effectiveWorkDir 与 default_cwd 均空时回退进程当前目录
  (否则 ls 工具拿到空路径触发断言崩溃)
- 集成测试 usage 断言同步 89edfa6 新语义(保留最后一轮真实值而非回合累计)

## 测试
- 新增 test/mock_halfopen.ps1(发部分 SSE 后挂起不关;20s 读超时安全网,
  看门狗失效时测试失败而非挂起)
- 新增 6 个看门狗测试:半开唤醒、Ctrl+Q 立即生效、手动/中途/同步压缩、
  模型列表拉取(均断言唤醒计数 >0 防假阳性;压缩断言 ≥2 证明重试链路)
- 全量 216/216 pass(全部 mock 就绪,0 skip);ReleaseSafe 构建通过