笔记

连接恢复了,离线消息为什么还没补齐?

手机从后台回来或切换网络后,聊天连接可能已经恢复,新消息也能收到,中间离线的那段记录却仍缺着。连接状态和历史是否完整,需要分开判断。

这个 Flutter App 使用 XMPP 接收实时消息,通过 HTTP 历史接口补偿离线记录。协议准备完成以后,历史请求才继续把漏掉的数据取回,转换后写入本地存储和界面状态。

每次重连都拉全部历史,可以吗?

消息少时可以这样做,但历史增长后会产生大量重复传输。另一种办法是记录同步边界,只取某条消息之后的数据;边界附近允许适量重叠,再按消息身份合并。

项目使用后一种方式。同步输入包括聊天会话、最后消息 ID、最后消息时间,以及可选的来源群。请求用 afterOriginId 表示从哪条消息之后继续拉取,部分分支还把起点时间往前退一段,留出重叠范围。

来源群是业务会话的一部分:同一成员可能分别在群甲、群乙的业务下与工作人员私聊,两段聊天不能共用一个“最后消息”。回退多少、边界是否包含在结果里,也必须与服务端规则匹配,不能照搬一个固定时间。

多个入口同时补偿,要合并还是排队?

恢复连接、进入会话都可能触发同步。可以让后来的调用共享进行中的任务,也可以串行执行,开始时重新检查是否仍需同步。

项目目前按会话与来源群取锁,同一范围的同步排队执行。它避免同时修改同一段数据,但没有自动把多个调用合成一个结果。

如果两个调用在排队前就拿到了同一份旧边界,后一个执行时仍可能重复请求。要减少这类重复,还需要在真正执行时重新读取边界,或者共享正在进行的任务;锁本身不负责这件事。

历史返回时已经换账号,怎样处理?

请求发出以后,用户可能退出 A 再登录 B。A 的响应仍能成功返回,但不能继续写进 B 的当前状态。仅取消等待也不够,已发出的请求未必停止。

项目在同步开始时记住账号与本轮会话代次,多个异步操作结束后重新检查。账号或代次不同就停止旧任务。退出再登录同一个账号也会增加代次,避免账号相同却已经换了一轮会话的结果继续生效。

失效时还会清掉房间锁映射,但增加代次、清映射都不是取消 HTTP 请求。它们约束的是旧结果接下来的处理,所以检查点要跟着异步流程走,不能只在发送前检查一次。

拉到空数组,与请求失败有什么不同?

空数组可以表示这轮没有更多消息;请求失败表示没有得到可靠答案。如果两者都转换成 [],上层就不知道该结束还是重试。

项目在历史补偿中使用严格错误处理,失败继续抛给会话层,安排有限重试,不拿失败批次的部分结果冒充完整成功。账号失效则结束旧任务,不能作为普通网络错误重试到当前账号。

整段同步目前还没有统一放进一个数据库事务。某一批请求成功后,入库和界面更新也需要分别核对。

返回上一页