Skip to content

下载过程无法取消,中断后的临时文件永久残留 #36

Description

@yujiezhang-ops

应用内的下载(桌面 Agent 安装/更新、运行时引导)一旦开始就无法干预,且异常终止后留下的临时文件没有任何机制回收。以下结论都在代码里核对过,不是推测。

1. 没有取消入口

internal/binding/services.go 没有暴露任何 Cancel 方法(全文件只有一处 "Request was cancelled" 的错误文案,没有可调用的取消 API)。

frontend/src/components/DownloadProgress.tsx 是纯展示组件,一个按钮都没有。而 DesktopAppSection.tsx 在下载期间把 5 个按钮全部 disabled={Boolean(pending)}

结果:用户点了下载之后只有两个选择——等它跑完,或者杀掉整个应用。超时是 installTimeout = 20 * time.Minutedesktopapp.go:102)和 RuntimeDownloadTimeout = 10 * time.Minutebootstrap.go:23)。选错镜像、网络慢、点错按钮,都得干等。

2. 正常错误路径的清理其实是对的

先说清楚不用改的部分,避免修的人白做:

  • downloadFiledesktopapp.go:742-751)拷贝失败时 os.Remove(destination)
  • macOS 装机路径有 defer os.RemoveAll(tempDir)desktopapp.go:366
  • Windows 路径用 keepInstaller 守卫 defer 删除(desktopapp.go:694-699
  • fetchTobootstrap.go)在拷贝失败和校验和不匹配时都 os.Remove(path)

返回 error 的路径都干净。 问题在于 defer 跑不到的时候。

3. 进程被杀 = 永久残留,而且不在系统 temp 里

这是真正的缺陷。installRuntimebootstrap.go:232-253)把临时文件放在 ~/.oneagent/runtimes,不是系统 temp:

target := runtimeDir(runtime.Home, runtimeID, entry.Version)
parent := filepath.Dir(target)          // ~/.oneagent/runtimes
...
file, err := os.CreateTemp(directory, ".download-")   // bootstrap.go:333
staging, err := os.MkdirTemp(parent, ".staging-")     // bootstrap.go:249

系统重启不会清理这个位置,OS 的 temp 回收策略也管不到。

grep 全仓库确认:没有任何启动时清理残留的代码.download-*.staging-*oneagent-desktop-agent-* 三类前缀都没有对应的扫描清理逻辑。

体积不小:runtimes.lock.json 里 Node.js 制品是 node-v24.18.1-*.tar.gz,约 50MB 一份。用户每次强退一个进行中的下载,就在自己家目录里留 50MB,反复几次就是几百 MB,而且他不知道那些点号开头的文件是什么、能不能删。

复现

  1. 触发运行时安装(装任意需要 Node 的 Agent),或桌面 Agent 的「更新」
  2. 下载进行到一半时强制退出应用(Cmd+Q 或 kill)
  3. ls -la ~/.oneagent/runtimes/.download-* 还在,且不会被任何后续操作清理

建议的修法

取消能力:给 binding 加一个 Cancel,把已有的 context.CancelFunc 接出去。取消路径本身已经通了(downloadFile/fetchTo 都用 NewRequestWithContextcontextError(ctx) 检查也铺好了),缺的只是从 UI 到 context 的这一段接线,以及 DownloadProgress 上的一个按钮。

暂停/续传:比取消复杂得多,需要 HTTP Range 支持和分片状态持久化。注意 fetchTo 里已有的注释明确说过,回退镜像时进度条要重新开始,因为「镜像的字节数说明不了官方源的情况」——续传要跨源就得处理这个。建议先做取消,暂停单独评估。

启动时清理:应用启动时扫 ~/.oneagent/runtimes,删掉超过某个时长(比如 24 小时)的 .download-*.staging-*。用时间阈值而不是无条件删,避免误删另一个正在运行的实例的进行中文件。系统 temp 里的 oneagent-desktop-agent-* 优先级低一些,OS 会回收,但同样处理更好。

相关代码

  • internal/desktopapp/desktopapp.go:717 downloadFile
  • internal/install/bootstrap.go:288 downloadArtifactfetchToinstallRuntime:232
  • internal/binding/services.go 缺 Cancel
  • frontend/src/components/DownloadProgress.tsx 缺取消按钮

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions