Files
wangbo 89a4ccd7e7
Test deployment public URL (Linux) / test-linux (push) Canceled after 0s
Test start.ps1 (Windows) / test-windows (push) Canceled after 0s
feat(deploy): 为更新组件增加定时维护与双保险
2026-10-08 09:23:25 +08:00

8.3 KiB

在线更新发布源修复与测试验收(2026-10-07)

本次修复已在 https://demo.51easyai.com 完成真实浏览器验收。候选镜像和测试发布源只用于测试环境;验收时尚未提交代码;该测试验收未更新正式 latest 镜像和仓库根目录的正式发布清单。

已复现问题与根因

  1. 测试站运行 3.22.0.20260930.3,页面从官方站运行版本接口检测到 3.23.1.20261006。
  2. 浏览器点击“立即更新”,任务 bcaa8c58-3628-42fc-af02-bc5f97bbc1c2 返回 no_update,实际版本和核心容器均未改变;页面仍提示有新版本。
  3. 更新器实际读取 /var/lib/easyai-updater/release-manifest.json,该路径由 data/deployment-config/legacy-compose.json 覆盖,内容仍指向旧版镜像。更新器不获取远程发布清单。
  4. 页面检测来源与执行来源不同;前端没有核对任务实际提供的版本,误把旧清单的“无需更新”作为新版已经完成更新。
  5. 正式部署仓库的发布清单也仍为 3.22.0.20261002.2;镜像仓库有后端 3.23.1.20261006 标签,但没有同版本前端标签。单纯改成本地另一条清单路径不能解决发布信息不一致。

最小修复及兼容性

  • 更新器默认从部署仓库 main 分支获取正式清单;私有源使用 UPDATE_MANIFEST_URL,离线部署须显式选择 UPDATE_MANIFEST_SOURCE=local。默认远程模式忽略历史本地路径覆盖,获取失败不会退回旧清单。
  • 受控模式的版本检测通过更新器获取可安装版本,不再取官方站当前运行版本;旧 Watchtower 模式保留原协议和检测缓存。
  • 新版客户端提交检测到的版本与发布标识;执行前重新获取清单,目标发生变化时拒绝安装另一版本。旧客户端只传 action 的请求继续兼容。
  • 任务保存完整清单,恢复及回滚使用同一快照。前端核对成功或“无需更新”的实际版本,避免错误提示;普通更新、强制更新和管理员新版提醒成功后均刷新检测结果。
  • 只对更高版本显示新版提示;受控更新拒绝自动回退到更低版本,包括强制更新。发布源不可用时显示“暂时无法检查”和“重新检查”。
  • 主要调用方:系统设置更新卡片、管理员新版提醒、任务恢复入口、自动更新调度及旧手动接口;未增加业务 Provider 或改变自动更新开关。

责任代码与本次改动位置:

  • 后端 apps/easyai-updater/src/release-source.ts、update-runner.ts、main.ts:发布源、目标固定、快照恢复与内部发布信息接口。
  • 后端 apps/easyai-server-main/src/app.service.ts、system-update/managed-update.service.ts、system-update/system-update.controller.ts:统一检测来源、兼容请求及目标字段传递。
  • 前端 composables/system-update/useSystemUpdateJob.ts:核对更新结果与检测目标;pages/admin/sys/operationConfig.vue 和 components/product-update/ProductUpdateAdminTouchpoint.vue:版本比较、检测异常提示及成功后刷新。
  • 部署仓库 docker-compose.yml、.env.sample:默认远程发布源与显式离线选项;原正式清单保留不变。

真实运行验收

先部署保留旧版本号的修复版控制入口作为测试基线;前端基线使用独立镜像,使实际任务能够验证网页容器替换。最终安装的镜像来自本次工作区构建。候选清单见同目录 release-manifest.candidate.json,不作为正式发布清单。

场景 结果
管理员通过真实登录界面进入系统设置并点击立即更新 只提交一次请求;任务 5a2968c5-9615-4e1f-9d88-79ada0f6aa06 成功,页面约 88.9 秒完成反馈
版本与容器核对 3.22.0.20260930.3 → 3.24.0.20261007;后端和网页容器实际替换,实时服务镜像无需变化
页面刷新 显示 3.24.0.20261007、已是最新,不重复弹出新版提醒
同版本普通更新 返回 no_update,不重复替换容器
强制更新确认后取消 不创建任务
发布源真实返回 HTTP 503 页面显示暂时无法检查,不能误报已是最新;恢复源后点击重新检查恢复正常
发布源改成旧正式清单 不提示有新版;点击强制更新后,任务 92182a3e-1948-4d82-99bc-aacb7c1c601f 在镜像拉取前被拒绝,原因 release_older_than_current
配置保留 核心服务环境变量、完整容器配置(除镜像)、端口、挂载路径及权限、网络地址和别名保持一致;宿主机 .env 与 docker-compose.yml 哈希不变
自动更新设置 验收前后均为开启,未改变原开关
更新器实际重启 已完成任务完整保留,恢复后仍提供同一测试发布信息;四个相关容器均健康

首次候选镜像补装运行依赖时移除了内部共享包,启动检查失败后恢复了原服务。补齐共享包并通过加载检查后,重新部署健康基线,再进行上述正式浏览器验收;没有把失败启动计为升级成功。

定向检查

本地检查使用 Node 22.22.0、Yarn 1.22.22,共 79 个不同的定向行为用例通过:

检查 结果与耗时
updater Node 测试 14 个通过,约 1.6 秒;覆盖真实 HTTP 发布源、源失败、目标变化、快照恢复及旧版回退保护
后端 system-update Jest 38 个通过,约 2.3 秒;包含新旧检测协议、实际 DTO 校验、自动更新调度和旧手动接口
前端任务与实际挂载测试 首轮 13 个通过,约 49 秒;追加后的设置与更新处理函数 5 个通过,约 4 秒,其中新增强制更新用例 1 个
版本工具和产品版本测试 13 个通过,约 0.13 秒
部署脚本隔离 dry-run 通过,约 4.3 秒,确认默认远程源及原部署契约
后端及更新器构建 通过,约 25 秒
最终前端生产构建 通过,约 168 秒

隔离环境中的旧实现会失败:前端将旧版 no_update 误判成功;更新器六个新增发布源场景不能满足预期。相同失败用例在修复后通过。HTTP 发布源测试使用受控 Docker 替身,真实容器替换另外通过测试站验收;没有用源码断言或构建替代运行验收。

证据与测试环境维护

完整本地证据目录:/Users/wangbo/.codex/visualizations/2026/10/07/01a11505-cae4-76e0-9ba9-235f6962b2b4/system-update-diagnosis。

  • acceptance-summary.json、browser-upgrade-acceptance.json、browser-acceptance.json:实际请求、任务、版本及异常场景。
  • acceptance-update-success.png、acceptance-final-card.png、acceptance-feed-unavailable.png、acceptance-older-release-blocked.png:真实页面结果。
  • config-before-browser.json、config-after-browser.json、mount-verification.json、final-verification.json:配置、健康及任务持久化核对。Docker 返回的挂载数组顺序不稳定,已按内容核对路径和权限一致。
  • *-tests.log、*-build*.log、updater-before-tests.log、frontend-before-tests.log:定向检查与修复前失败记录。

测试环境保留内部测试发布源容器 easyai-update-release-feed,无新增宿主机端口。任务专用配置位于 /root/easyai/data/update-acceptance-20261007,其中 accepted.json 和更新后的 baseline.json 指向实际验收镜像;rollback.json 保留原镜像引用。维护测试站时须使用原 Compose、原 legacy override 与该目录下 accepted.json 的组合,不能将该测试清单误发布成正式清单。

未验证范围及正式发布条件

  • 未发布生产,未执行全站业务回归或全量质量门禁;健康检查和更新入口验收不能代表全部业务兼容性。
  • 定时自动更新实际到点执行未验收,调度逻辑已做定向测试;自动更新设置保持原值。
  • 已测试持久化快照恢复,并实际重启验证已完成任务;没有在真实容器替换过程中故意中断 updater。旧 updater 未带清单快照的在途任务跨版本迁移尚未验收,升级更新器前应先确认没有执行中的更新任务。
  • 正式发布时须一起交付 updater 1.2.0、后端和前端,并在镜像完整发布后同步正式清单的版本、发布标识、不可变摘要及大小。只改官方站版本或只推送 latest 仍无法代表客户可安装的新版本。