记一次 Electron App 在 Windows 上自动更新问题排查

1,438 阅读10分钟

最近团队在处理 Whale Trading Terminal 在 Windows 平台上无法自动更新的问题时,发现了一些有意思的细节,在这里分享给大家。

什么是 Whale Trading Terminal(WTT)

桌面交易专家 Whale Trading Terminal 是长桥推出的一款专门针对交易员/经纪人的专业交易前台软件,根据操作员自身操作习惯自定义面板组件和内容排布,设置不同操作快捷键,在前台实现日常的盯盘交易、订单处理、信息查询、账目调整等操作。

  • 灵活的自定义面板组件布局
  • 支持上百种技术指标
  • 丰富的快捷键设置支持全键盘操作
  • 实时查找全量历史数据
  • 面向全球市场设计,多语言多系统支持

同时,长桥拥有面向专业投资者使用的桌面端交易软件 Longbridge Pro,可以前往 - longportapp.cn/zh-CN/downl… 下载使用。

问题背景

Whale Trading Terminal 是一个基于目前广泛使用的 Electron 框架开发的桌面端 App,为了给用户提供最新功能以及最好的使用体验,使用了 electron-builderelectron-updater 模块协同工作来给 App 添加自动更新、安装的能力,这样在新版本发布后,用户可以方便、快速地更新到 App 最新版本。

但是最近有收到用户反馈,在 Windows 系统上运行自动更新安装程序时,更新安装程序无法自动关闭当前仍在运行的 Whale Trading Terminal 实例,即使用户选择手动重试,也无法由更新安装程序完成这个操作,只能由用户主动关闭当前正在运行的 Whale Trading Terminal 才可以进行下一步操作。

在更新安装程序安装过程中,会持续提示以下内容:

在截图所示这一步中,重试永远得不到正确的响应,会一直循环在这一步,或者用户只能取消整个安装流程。

预期正确行为

在之前的版本中,Whale Traiding Terminal 的更新安装程序是可以正确地执行整个安装过程,并没有碰到这个异常情况,例如在正确情况下,更新程序会提示以下内容:

在点击确定后,更新安装程序将会正在运行的 Whale Trading Terminal 实例关闭,继续后续安装步骤。

更新机制

在排查问题前,我们先来了解一下一个典型的 Electron App 是如何在 Windows 系统上执行更新安装程序的。

Electron App 在 Windows 系统上的更新流程

  1. 版本检查:App 通过 electron-updater 提供的方法获取到最新的包版本,比对当前版本,如果有更新则进行下载
  2. 下载更新:会下载新的应用程序文件并将其保存在本地临时目录下
  3. 应用程序更新: 这里一般有两种处理方式,一种是立即更新,一种是下次软件启动时更新。将新版本的应用程序文件应用到本地安装的 Electron 应用程序中,这里可能会涉及到现有文件的更新和替换
  4. 重启应用程序:为了使更新生效,通常需要重新启动应用程序

为什么要关闭正在运行的实例

在 Electron App 更新安装程序执行时,需要主动退出正在运行的实例,这是由于操作系统中文件系统管理的机制所决定的。

在 Windows 上,文件系统中的文件默认情况下是 "打开即锁定" 的,这意味着当一个进程打开一个文件时,其他进程无法修改或删除该文件,直到该文件被关闭。

这设计的目的是确保数据的完整性和一致性。通过将文件锁定,操作系统可以防止其他进程在同一时间对文件进行写入或删除操作,从而防止数据损坏或丢失。这对于多进程或多线程环境下的并发访问是非常重要的。

所以在 Windows 系统上,Electron App 的更新安装程序需要将正在运行的实例关闭,以便将 App 所使用的相关文件资源释放,从而完成 App 所依赖资源文件的更新和替换。

同时,突然关闭正在运行的实例可能会造成用户正在进行的操作中断,或者正在输入的数据丢失,因此,安装程序需要检测是否存在正在运行的实例,并提示用户确认关闭正在运行的应用程序,如果用户同意,再在安装过程中尝试关闭它。

这些步骤确保了新版本的文件能够被正确地复制并替换,避免了潜在的冲突和错误。

问题排查

什么是 electron-builder 和 NSIS

Whale Trading Terminal 使用 electron-builder 这个开源工具来构建各个平台的安装包,简化发布流程。

electron-builder 是一个用于构建和打包 Electron 应用程序的开源工具。它简化了将 Electron 应用程序打包成可执行文件和安装程序的过程。通过 electron-builder,开发者可以轻松地为不同的操作系统生成可执行文件,并创建适用于 Windows、macOS 和 Linux 的安装程序。

而在 Windows 系统上,electron-builder 依赖于 NSIS 来构建安装程序。

NSIS(Nullsoft Scriptable Install System)是一个用于创建 Windows 安装程序的免费开源脚本驱动的系统。它允许开发者通过编写脚本定义安装过程,包括文件复制、注册表项添加、环境变量设置等。NSIS 可以生成独立的可执行安装程序,这使得在 Windows 系统上分发应用程序变得更加方便。

NSIS 使用脚本驱动,因此我们可以通过查找相关脚本的方式来排查这个问题。

开始排查

根据前面更新安装程序安装过程消息框所提示的内容,我们在整个项目的代码中搜索“正在运行”这个文案。

在搜索结果中,我们可以看到在 app-builder-lib 这个依赖包中包含这个字符串,并且根据文件内容可以判断这是一个它所使用的多语言包。

在这个多语言包中,可以看到对应这个消息提示的 key 为 appRunning,可以继续搜索这个多语言 key 在哪里使用。

通过这个字符串,可以看到 electron-builder 编写的 NSIS 预置脚本,在这个脚本中,通过名称可以看到有一个专门用于检测程序是否有实例正在运行的宏 _CHECK_APP_RUNNING

定位问题

根据前面异常流程和正确流程的对比,在异常的情况没有弹出“正在运行”提示,分析这段代码的逻辑后可以发现,我们需要排查一下为什么在 if 语句中没有进入 $R0 == 0 这个分支。

从代码里可以看到,在 if 语句判断前,它调用了另外一个宏 FIND_PROCESS 来进行进程查找操作,并将查找结果赋值到 $R0 中。

继续找到 FIND_PROCESS 这个宏的代码:

在这里可以看到,它最终使用了命令行程序执行 tasklist 命令来输出所有匹配当前应用名称的进程列表,并使用 find 命令查找是否有匹配的进程存在。

为了查看它实际执行的命令是什么,我们在 FIND_PROCESS 添加一个消息框来将它实际执行的命令显示出来:

重新执行更新安装程序,得到以下结果:

拿到 FIND_PROCESS 执行的命令后,我们在命令行中手动执行一次看看,先运行第一段 tasklist 部分:

tasklist 的确列出了 Whale Trading Terminal 所有的进程列表,但是似乎有一点点不对劲,这里的映像名称是 Whale Trading Terminal.ex,相比完整的映像名称,缺少了 exe 的最后一个 e。

会是这个原因引起的吗?

接着加上后半段 find 部分,输入完整命令,命令行中没有得到任何输出:

这时,FIND_PROCESS 会认为当前并没有正在运行的 Whale Trading Terminal 实例,从而不会执行提示用户关闭正在使用的程序的逻辑。

找到答案

再回头看为什么在 FIND_PROCESS 没有正确执行时,更新安装程序会一直提示无法关闭正在运行的程序,我们找一下 无法关闭 这个字符串,找到对应的多语言 key 为 appCannotBeClosed

同时找到一个用于卸载旧版本的宏 uninstallOldVersion,可以看到,它里面会尝试卸载旧版本的 Whale Trading Terminal:

上一步中,FIND_PROCESS 由于 bug 导致没有发现正在运行的进程,再结合上面提到 Windows 中文件系统的机制,Whale Trading Terminal 正在运行时,卸载程序是没有办法替换文件的,这就会导致卸载程序一直无法正确执行,在 uninstallOldVersion 尝试多次都无法解决后,就会提示用户无法关闭正在运行的程序了。

到这里,我们终于找到了为什么 Whale Trading Terminal 为什么在更新安装程序中无法被关闭的原因:

  1. 在 NSIS 的安装脚本中,检测是否有正在运行的进程时,由于 tasklist 命令的限制,在输出映像名称时会在 25 个字符时截断
  2. 从而导致 find 使用完整进程名称进行匹配时,匹配不到任何结果,会使得更新安装程序认为当前并没有正在运行的 Whale Trading Terminal 实例
  3. 这就导致更新安装程序的前置步骤卸载旧版本程序无法正确执行,最终导致更新安装程序一直卡在尝试关闭正在运行的实例

解决问题

既然知道原因,那么这个问题就很容易解决了。

首先通过查询 tasklist 的帮忙文档,可以看到里面可以指定输出格式:

可以看到有一个参数 /FO 用于指定输出结果的格式,它支持 TABLE、LIST 和 CSV,默认情况下是 TABLE,即之前会截断的格式,这里尝试将 tasklist 的输出格式改为 CSV 看看:

果然可以得到完整的进程名称。

在本地通过直接修改 npm package 代码的方式将 electron-builder 预置的 NSIS 脚本中对应的代码修改掉,再打包测试后,更新安装程序就可以正常检测正在运行的 Whale Trading Terminal 实例并将它关闭,因此整个更新安装程序就可以正确执行后续步骤了。

至此,一个 Electron App 在 Windows 系统中无法通过更新安装程序自动关闭正在运行实例的问题排查完毕,并且找到解决方案。

回馈社区

在找到解决方案并实际验证可行后,已经就修复代码向 electron-builder官方仓库提出 Pull Request,目前已经合并进入 app-builder-lib@24.11.0

github.com/electron-us…

号外

长桥 Longbridge Pro 是由长桥证券为专业投资者而开发的专业交易平台,具有以下特点:

  • 机遇由你布局

    • 分屏盯盘,多端联动,无缝操纵;各类卡片式自定义组件任你调遣,你的交易由你布局。
  • 指间运筹画策

    • 超百种技术指标,联手 Trading View 12 种多维度划线工具,把你的策略推向价值新高度。
  • 大招一键即发

    • 一键快捷下单,配合港股涡轮牛熊、美股期权等多种衍生品,交易高手放大招得心应手。

欢迎下载试用:longportapp.cn/zh-CN/downl…