给 Electron 自动更新加灰度时,我会先把观察点和回滚路写清楚
最近给一个 Electron 桌面端工具补自动更新能力时,我先问了一个很朴素的问题:用户点了“检查更新”之后,我们到底能不能知道它卡在了哪一步。自动更新看起来像一条短链路,客户端请求更新源,下载包,重启安装。实际落到桌面端后,麻烦会散在签名、发布通道、网络代理、安装器锁、灰度比例和用户主动退出这些细节里。只要其中一个环节没有记录,线上反馈就会变成一句“更新失败了”。

原创示意图:从桌面客户端、更新元数据、遥测事件到回滚控制路径,把灰度发布拆成可观测节点。 来源:Codex image generation
问题背景
Electron 官方 autoUpdater 文档说明它是一个 EventEmitter,并列出了 checking-for-update、update-available、update-not-available、update-downloaded 和 error 等事件。文档也提醒内置自动更新主要支持 macOS 与 Windows,Linux 通常交给发行版包管理器处理。这个边界让我把自动更新当成一条跨平台状态机来做。
我遇到的具体场景是,产品希望先给少量用户推新版本,观察稳定后再逐步扩大。electron-builder 的自动更新文档提到,electron-updater 会生成并上传 latest.yml 一类元数据,客户端再查询发布服务器;灰度发布可以通过 stagingPercentage 控制比例。如果灰度版本出了问题,修复版需要使用更高版本号,因为已经拿到坏版本的用户不会因为同一个版本号重新被修好。
踩坑和关键难点
第一个坑是重复检查。Electron 文档写得很直接,checkForUpdates() 调两次会下载两次更新。桌面端里菜单、托盘、启动任务和设置页都可能触发检查。我的处理方式是给主进程加一个 update_check_id,同一窗口期内的重复请求只订阅已有状态,不再触发新的下载。
第二个坑是灰度没有回放证据。只看 update-downloaded 还不够,我需要知道当前用户命中了哪个通道、看到的目标版本、灰度百分比、元数据发布时间、下载耗时和最终安装动作。GitHub Releases 文档把 release 定义成可分发的软件迭代,可以带 release notes 和二进制文件链接;如果发布资产放在 GitHub,我会把 release id、tag 和 asset 名称也写入排查记录。
第三个坑是回滚容易被说成“撤回”。对自动更新来说,可靠的回滚通常是发布一个更高版本的修复包,或者把通道元数据指向新的安全版本。直接删除资产可能让一部分客户端进入更难解释的失败状态。
解决思路
我在主进程里封装了一层 UpdateCoordinator,它只暴露 check、download、installLater、quitAndInstall 四个意图。每个意图都会写一条结构化事件,字段包括 currentVersion、targetVersion、channel、stagingPercentage、provider、releaseTag、eventName、durationMs、errorCode 和 userAction。渲染进程只展示状态,不直接碰更新器实例。
灰度配置也不散落在 CI 脚本里。我会为 stable、beta、internal 三个通道保存一份发布清单,记录版本号、提交 SHA、构建号、签名状态、更新元数据路径和回滚目标。发布时先把清单写进构建产物,再上传元数据,最后用脚本读取远端结果做一次校验。这样排查时能确认客户端看到的内容,和 CI 刚刚发布的内容是否一致。
关键步骤
第一步是把自动更新事件接进日志。error、checking-for-update、update-available、update-not-available、download-progress、update-downloaded 都要记录,日志里不要写 token 和完整私有 URL,只保留 provider、host、版本和错误摘要。
第二步是给灰度加闸门。发布脚本默认只允许从 5% 开始,扩大比例需要读取最近一段时间的启动失败、下载失败和安装后首启成功率。这个阈值不一定复杂,关键是每次调比例都留下操作者、时间和理由。
第三步是演练回滚。我会准备一个空改动的补丁版本,在测试环境里模拟坏包已经被部分用户下载,再发布更高版本号的修复包,确认旧客户端能拿到新元数据,安装后能把本地状态从 downloaded 或 failed 收敛到 ready。
可复用经验
自动更新要优先关注可观测的发布状态,弹窗文案放在后面。客户端要知道自己看到了什么,服务端要知道自己发布了什么,CI 要能证明元数据和资产匹配。把这三件事串起来后,灰度发布才有继续扩大或及时收住的依据。
我现在做 Electron 自动更新,会先写状态表和回滚剧本,再接 UI。只要 check、download、install、rollback release 这些节点都有事件,后续无论使用 Electron 内置 autoUpdater,还是使用 electron-builder 生态里的 electron-updater,排查路径都会清楚很多。