跳到主要内容

← 返回开发日志

传输恢复:已经完成什么,暂时不承诺什么

Dogfood 中 Transfer recovery
  • #传输
  • #已知限制

传输恢复这个词容易被误解

“传输恢复”听起来像是一个开关:断了就自动续传,重启了也接着传。在 ConchTerm 的当前阶段,这件事要分两层说清楚,因为它们能承诺的程度差很多。

已经完成的部分

运行期的传输控制和恢复是闭环的:

  • 队列与状态机:每个会话默认 2 个并发、全局 4 个并发,支持 queued / running / paused / failed / canceled / completed 等明确状态转换,且转换受 canTransition 强制约束。
  • 暂停、继续、取消、重试:可以在传输抽屉里对单个任务或批次做这些操作。
  • 运行期 offset 续传:上传和下载都先写 .part.<taskId>,完成后原子 rename 到最终路径。只要应用还在运行、会话和授权还在、partial 文件还在、源文件 size/mtime 没变,断线后可以按 offset 继续。
  • 冲突预检和批次策略:传输前预检目标冲突,支持 overwrite | skip | rename 批次策略。
  • 崩溃安全的任务日志TransferJournal 用原子 JSON 文件记录任务,恢复中心能读取并展示可恢复任务。
  • 恢复中心(只读):把活动、可恢复、被阻塞和历史的任务以 display-safe 的 DTO 展示出来。

这些都是现在就能用的能力,不是路线图。

暂时不承诺的部分

诚实说明边界,避免误解:

  • 应用重启后的一键 resume 还没接通。 重启后,运行期凭据库和路径授权会被清空,持久化的传输任务缺少会话上下文,主进程也没有接收这些持久化任务的入口。因此恢复中心目前以“pending”标签诚实降级——它告诉你哪些任务可恢复,但需要你手动重新发起,而不是点一下就续传。
  • upload 方向的 partial 文件清理还没实现。 如果你在 discard 一个上传任务时选择删除 partial,目前只能清理下载方向的本地 partial;上传 partial 在远端,需要重新建立 SFTP 连接才能 best-effort 删除,这部分随 resume 管道一起做。
  • 不计算 checksum。 运行期 offset resume 依赖源文件 size/mtime 校验,不做内容级校验或去重。

这两项是技术债务登记里明确记录的暂缓项,对应 TD-017(resume 生产入口)和 TD-018(upload partial 清理)。它们不是缺陷被隐藏,而是阶段边界。

为什么不直接承诺“重启后自动恢复”

把“重启后自动 resume”做对,需要几件事同时成立:

  • 凭据能安全地跨重启恢复(macOS Keychain 持久化已就位)。
  • 路径授权能跨重启重建。
  • 主进程有一个接收持久化任务、重新绑定会话的入口。
  • 源文件变化的校验和 UI 降级路径要清晰。

在把这些都做完、并且经过集成和 E2E 验证之前,声称“重启后自动续传”会误导用户。我们选择先让恢复中心诚实展示状态,等管道接通后再开放一键 resume。

用户现在该怎么做

如果你在传输中断后需要继续:

  • 应用还在运行:直接在传输抽屉里重试,能走运行期 offset 续传的就续传。
  • 应用已经重启:去恢复中心查看可恢复任务,手动重新发起受影响的传输。
  • discard 上传任务后想清理远端 partial:目前需要你手动处理远端 .part 文件,因为自动清理尚未实现。

这些操作方式写在这里,是希望你在 dogfood 阶段就能正确预期行为,而不是在出错时才发现边界。

相关事实源

本文内容可追溯到以下仓库文件:

  • docs/QUALITY_SCORE.md
  • docs/exec-plans/tech-debt-tracker.md