v2.34-02 静默截断:10,000 个会话与 500 条消息是怎么被发现的

v2.34-02 静默截断:10,000 个会话与 500 条消息是怎么被发现的

做备份规划时,最容易忽略的不是加密算法,而是「你以为备份了,其实没备份全」。

这一版开工前盘点导出路径,发现两个硬上限:

  • 会话最多导出 10,000 个;
  • 每个会话最多导出 500 条消息。

它们没有报错,没有警告,manifest 也不记录真实条数。用户看到的是一份「成功」的归档,实际上少了数据。

一、上限是怎么来的

最初的上限是列表接口的默认值。

会话列表用于界面展示,默认返回最近 100 条;消息列表用于对话渲染,默认 200 条。备份逻辑复用了这些接口,只是把参数调大,调到了 10,000 与 500。

问题在于:列表接口的语义是「取前 N 条」,不是「取全部」。

备份需要的是后者。

二、为什么静默最危险

如果导出直接报错「会话过多」,用户至少知道有问题。

静默截断的问题是:

  • 归档能打开;
  • 预检能通过;
  • 恢复也显示成功;
  • 但历史消息少了一部分。

等到用户真正需要那份旧消息时,才发现备份里没有。

这类问题不会在测试里自然暴露,因为测试数据通常只有几条。

三、修复思路:全量读取,而不是调大上限

修复没有继续调大数字,而是新增「全量读取」的仓储方法:

text 复制代码
listAll()                          // 全部会话,按创建时间排序
listAllByConversation(convId)      // 单会话全部消息,按创建时间与 rowid 排序

备份路径只调用这两个方法,不再复用列表接口。

列表接口保留原有分页语义,界面不受影响。

四、排序为什么重要

全量读取必须稳定排序。

  • 会话按 created_at, id 排序;
  • 消息按 created_at, rowid 排序。

rowid 用于处理同一毫秒内写入的多条消息。没有它,恢复顺序可能在不同机器上不一致。

五、manifest 记录真实条数

只改读取还不够,还要让核对能发现问题。

manifest v9 在 conversations 轨增加 messageCount,记录实际导出的消息条数。

恢复核对时:

  • v9 归档按「会话 + 消息 + 分支 + 分支事件」比对;
  • v8 归档缺少消息数,回退为只比会话数。

这样新归档的差异能被看见,旧归档也不会出现假差异。

六、上限并没有消失

归档仍然有 500MB 上限。

区别是:超过上限会直接失败,不产出半份文件。用户会看到「归档过大,请分批导出」,而不是拿到一份不完整的归档。

上限从「静默丢弃」变成「显式拒绝」,这是这一版最重要的行为变化。

七、测试怎么覆盖

新增用例直接构造 501 条消息:

  • 导出;
  • 解包读取 conversations.json;
  • 断言消息数组长度为 501;
  • 断言 manifest 的 messageCount 为 501。

这个用例很朴素,但它能防止上限被重新引入。

八、一条经验

备份路径不要复用面向界面的列表接口。

界面接口的默认值、分页与排序都是为展示服务的;备份需要的是「全部、稳定、可核对」。

当两者复用时,上限会以「默认值」的形式悄悄进入备份,而且不会报错。

相关推荐
vaskilab22 分钟前
Agent 上线后翻车的 6 种死法:一个 20 万人规模项目的四版重构实录
后端
鶴哥只手遮天1 小时前
《rustc 内幕》第 1 章 全景:rustc 编译流水线与 crate 版图
后端·rust·开源
starzy19901 小时前
深入理解Scala隐式值:编译期自动装配
开发语言·后端·scala
装不满的克莱因瓶3 小时前
设计模式之策略模式核心概念和应用场景
java·后端·设计模式·架构·系统架构·策略模式
特立独行的猫A9 小时前
用仓颉语言 cj-tauri 框架,五分钟给娃做了个鸿蒙形近字游戏
java·后端·python
码事漫谈12 小时前
我花了一周时间,看AI公司怎么"管"AI,结果越看越后背发凉
后端
爱学习的程序媛15 小时前
Python常用框架梳理
开发语言·后端·python·ai·web·后端框架·python框架
GISer_Jing15 小时前
Agent核心内容
后端·ai·langchain
budingxiaomoli16 小时前
Spring统一功能处理
java·后端·spring