文章

从一次观看同步抖动到可验证的 Beta 发布

记录 Emby Watch Together 如何处理短暂远控能力抖动,并把诊断、参与者重同步和发布验收边界写进版本流程。

Emby Watch Together 最近一次值得记录的改动,起点是一个很具体的播放同步异常。

双方已经完成起播同步并进入观看状态,其中一端的远程控制能力短暂丢失。旧逻辑会把它当成同步资格失效,另一端可能因此被暂停,房间也需要重新进入同步流程。实际播放有时只是连接抖了一下,状态机却已经开始处理更严重的故障。[2]

这类问题不能靠简单放宽判断解决。放宽过头以后,真正换片、停播、断线或会话变化也可能被掩盖。最后采用的路径,是给特定状态加一个有边界的恢复窗口,再把诊断和人工重同步补进发布流程。

先给短暂抖动一个边界

修复只作用于已经处于 Watching 的房间。两端仍然需要保持同一会话和同一视频,当前快照需要可用,播放身份需要连续,实际命令能力仍然能够使用,且没有正在等待确认的命令。[3]

满足这些条件时,远控标志短暂丢失不会立即触发暂停。版本给它最多 8 秒恢复时间。恢复窗口内不发送新的暂停、继续、拖动或提示命令,避免把命令发给暂时不可用的连接;能力恢复后,再继续处理窗口期间真实发生的播放变化。[2]

恢复窗口有几个明确的出口:

  • 会话或视频身份变化;
  • 参与者数量或快照结构变化;
  • 有效命令能力不再满足条件;
  • 已经存在待确认命令;
  • 远控异常持续超过 8 秒。

任何一个条件发生,房间都会回到原有的安全处理路径,暂停并重新同步。代码里的恢复签名绑定了用户、会话和视频身份,避免一个旧连接的短暂状态被误用于新的播放上下文。[3]

这次改动的重点在于,把“可以短暂等待”的情况从其他失败原因中分离出来。

让诊断先于猜测

有了恢复窗口以后,下一步问题变成了如何知道房间为什么没有继续同步。只看最终的暂停结果,很难判断故障来自快照缺失、远控能力、Barrier、Pending,还是参与者身份发生了变化。

v1.4.4.1 增加了只读房间诊断接口和页面。诊断内容包括状态原因、快照健康、会话能力、Pending、Barrier、恢复窗口、最近结果和有界事件记录。[4]

诊断导出使用字段白名单和稳定别名,排除了真实用户名、用户或会话 GUID、Token、路径和底层异常文本。[4] 这样做有两个好处。排查时有足够的状态信息,分享诊断结果时也不需要把服务端内部数据整包带出去。

这里还需要保留一个验证边界。诊断里的位置、能力和确认延迟是服务端观察值,它们不能证明播放器已经执行了命令,也不能单独证明两端已经对齐。[4]

因此,诊断页面承担的是缩小问题范围的工作。它能告诉我状态机看到了什么,不能替代真实客户端播放验收。

把重新同步交给参与者

管理员手动操作适合处理已确认的房间故障,观看过程中的普通参与者也需要一个低风险的自助入口。v1.4.4.2 增加了参与者请求重新同步的能力。[5]

请求进入房间 gate 后,服务端会重新检查成员关系、加入状态、服务器身份、快照保护、Barrier 和 Pending 状态。通过检查后,流程复用现有的 Waiting → Barrier 路径;同步正在进行或短时间内重复点击,会返回稳定的 busy 原因。[5]

页面只向已经加入房间的非管理员显示这个入口,并把 accepted、busy 和 unavailable 分开反馈。这样用户能知道请求已经受理、当前同步忙碌,还是房间暂时没有足够的服务端状态完成操作。

这个入口没有直接清理正在确认的命令,也没有绕过服务端的房间状态。它只是把一次受约束的重新同步请求交给现有状态机处理。

发布时把证据边界写出来

这几轮改动最后被整理成 beta 发布。对外发布时,我把验证结果分成几层:

验证层 能说明什么 仍然不能说明什么
单元测试 状态转换、恢复窗口和请求门控符合预期 真实客户端一定按预期播放
自动构建与产物检查 代码能构建,发布物可以被检查 两台设备之间的连接和时钟一定正常
管理页面验收 诊断入口、脱敏导出和反馈状态可用 播放器已经完成双端对齐
双客户端播放 真实 Emby 环境中的播放、暂停和重同步行为 其他客户端版本和网络条件一定相同

v1.4.4.2 的发布说明明确写了自动测试和构建已经通过,同时把参与者重新同步的双客户端播放、Barrier 和 Pending 实机验收列为后续工作。[5]

这条边界必须保留。测试通过和发布物生成,是可以复核的结果;它们不能被改写成“真实播放已经完全验收”。对于同步类插件,实机验收需要同时观察服务端日志、两端客户端行为和房间状态变化,缺一项都只能算阶段性证据。

这次发布真正解决了什么

这几轮工作并没有一次性消灭所有同步问题。它完成了几件更容易维护的事情:

  • 给短暂远控抖动定义了 8 秒和状态身份边界;
  • 给状态机增加了可读、可脱敏的诊断出口;
  • 给普通参与者提供了受门控的重新同步请求;
  • 给 beta 发布写清楚自动验证和实机验收的区别。

对我来说,最有价值的变化是排查路径变短了。遇到一次不同步时,可以先看状态机记录的失败原因,再决定需要等待、请求重新同步,还是保留双端日志继续排查。发布说明也会同时写下已经证明的部分和仍需验证的部分。

同步系统的可靠性不只来自更复杂的算法,也来自每一次状态转换都有边界,每一项结论都有对应的证据。

Sources

[2] https://github.com/hope140/EmbyWatchTogether/releases/tag/v1.4.3.2 — EmbyWatchTogether v1.4.3.2 [3] https://github.com/hope140/EmbyWatchTogether/commit/c978c1330d08c7077555d5a8f4402f6790f100e3 — EmbyWatchTogether remote-control recovery commit [4] https://github.com/hope140/EmbyWatchTogether/releases/tag/v1.4.4.1 — EmbyWatchTogether v1.4.4.1 [5] https://github.com/hope140/EmbyWatchTogether/releases/tag/v1.4.4.2 — EmbyWatchTogether v1.4.4.2