fix(update): 源码部署改为暂存加改名,中断不再留下残缺 app/ - #619
Open
qiyinxi wants to merge 1 commit into
Open
Conversation
copyToRoot() 原来对每一项先 rmSync 掉目标、再逐文件 copyFileSync。删完之后、 复制完成之前的任何中断——进程被杀、断电、单个 copyFileSync 因杀软/占用抛 EPERM/EBUSY——都会留下一个残缺的 app/,缺哪些模块取决于复制停在哪一步。 线上表现为 ModuleNotFoundError / ImportError 家族,落在 lifespan 里的那几个 会让后端完全起不来且无提示。 改为: - 先把新内容整个复制到 <item>.new,这一步失败时 <item> 还原封不动 - 再 rename(<item> -> <item>.old) + rename(<item>.new -> <item>) 换上, 空窗从「整个复制耗时」缩到两次元数据操作之间 - 换成功才删 .old;任一步失败则把 .old 换回去并清掉 .new - .git 挪到 app/res/main.py 之后,避免中断后「版本已最新」的假象盖住残缺源码, 否则后端 get_git_version() 认为 HEAD 已最新,用户失去重新拉取的入口 Closes AUTO-MAS-Project#544 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
审查者指南源码部署改为逐项完整写入 原子源码部署时序图sequenceDiagram
participant RepositoryService
participant Source as SourceTree
participant Stage as Item.new
participant Target as Item
participant Backup as Item.old
RepositoryService->>Source: statSync(srcPath)
RepositoryService->>Stage: removePath(stagePath)
RepositoryService->>Stage: copyDirectory or copyFileSync
alt copy succeeds
RepositoryService->>Target: renameSync(dstPath, backupPath)
RepositoryService->>Target: renameSync(stagePath, dstPath)
RepositoryService->>Backup: removePath(backupPath)
else copy or switch fails
RepositoryService->>Stage: removePath(stagePath)
alt target was backed up
RepositoryService->>Target: removePath(dstPath)
RepositoryService->>Backup: renameSync(backupPath, dstPath)
end
end
部署项顺序流程图flowchart LR
App[app.new -> app]
Res[res.new -> res]
Files[main.py, requirements.txt, LICENSE, README.md]
Git[.git.new -> .git]
App --> Res
Res --> Files
Files --> Git
文件级变更
可能关联的问题
提示和命令与 Sourcery 交互
自定义使用体验访问你的控制面板:
获取帮助Original review guide in EnglishReviewer's Guide源码部署改为逐项完整写入 Sequence diagram for atomic source deploymentsequenceDiagram
participant RepositoryService
participant Source as SourceTree
participant Stage as Item.new
participant Target as Item
participant Backup as Item.old
RepositoryService->>Source: statSync(srcPath)
RepositoryService->>Stage: removePath(stagePath)
RepositoryService->>Stage: copyDirectory or copyFileSync
alt copy succeeds
RepositoryService->>Target: renameSync(dstPath, backupPath)
RepositoryService->>Target: renameSync(stagePath, dstPath)
RepositoryService->>Backup: removePath(backupPath)
else copy or switch fails
RepositoryService->>Stage: removePath(stagePath)
alt target was backed up
RepositoryService->>Target: removePath(dstPath)
RepositoryService->>Backup: renameSync(backupPath, dstPath)
end
end
Flow diagram for deployment item orderingflowchart LR
App[app.new -> app]
Res[res.new -> res]
Files[main.py, requirements.txt, LICENSE, README.md]
Git[.git.new -> .git]
App --> Res
Res --> Files
Files --> Git
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #544
问题
copyToRoot()对每一项先rmSync掉目标、再逐文件copyFileSync。删完之后、复制完成之前的任何中断——进程被杀、断电、单个copyFileSync因杀软/占用抛 EPERM/EBUSY——都会留下一个残缺的app/,缺哪些模块取决于复制停在哪一步。没有临时目录、没有回滚、没有部署后校验。线上表现是
ModuleNotFoundError/ImportError家族,至今已在 Sentry 上观察到四种形态(AUTO-MAS-BACKEND-56/51/4R/4M/49/5H/6A/6M/6P/6T/6Y…):app/**/xxx.py子模块ModuleNotFoundErrorapp/api/__init__.pyImportError (unknown location)app/task/__init__.pyAttributeErrorImportError: cannot import name 'X' from 'app.utils'落在
lifespan里的那几个会让后端完全起不来且无提示。改动
按 issue 里的建议改成「暂存 + 改名」:
另外把
.git从第一位挪到最后一位。原来.git先复制,若.git成功而app中断,后端get_git_version()会认为 HEAD 已是最新、标题栏不再提示「后端有更新」,用户因此失去重新拉取的入口,残缺状态可以一直留到下次启动。抽出
removePath()复用原先那段「是目录就 rmSync、是文件就 unlinkSync」。磁盘占用
<item>.new会让app/与.git/在切换瞬间各占两份。app/是源码、只有几 MB;.git/在optimizeStorage()做过 gc 之后也不大。相对「更新失败把用户装崩」,这个代价我认为值得,但如果你们觉得.git那份不该翻倍,可以只对app/res用暂存路径、.git保持原逻辑——告诉我我来改。没有一起改的
issue 里提到的第二个加重因素没动:
frontend/src/views/Initialization/index.vue:501handleSkip()允许用户在源码拉取失败后点「跳过此步骤」,状态被直接改成success并继续在残缺的树上启动后端。那是一个 UX 取舍(跳过按钮本身有存在意义),我不替你们决定,留在 #544 里没关掉的话可以单开一条。本地验证
那条失败是
electron/services/backendService.test.ts > managed 模式 > 不传 --repo、不先跑 environment ensure,--app-root 就是用户数据根,dev 上本来就红(在干净的upstream/dev上重跑同样失败),与本 PR 无关。新增
electron/services/repositoryService.test.ts,4 条:.new/.oldapp/三个文件全部完好、无残留.git排序app.new→res.new→.git.new这套测试对旧代码是红的:把本 PR 的
repositoryService.ts还原成 dev 版本后重跑,「复制中途失败」与「.git排序」两条失败(2 failed | 2 passed)——不是写完就绿的空测试。没有做真机手测:需要真的在部署中途杀掉 Electron 主进程来验证,本地没有安装态环境。改动集中在文件系统操作,逻辑由上面的测试覆盖,但这条路径一旦坏掉就是用户装不上,建议合并前有人在真实安装目录上跑一次完整的源码更新。
请审阅
@DLmaster361 这块是你写的,尤其请看「磁盘占用」和「没有一起改的」两节的取舍。确认后请你自行合并,我不代合。
Sourcery 摘要
使源代码部署具备原子性并支持恢复,从而确保中断的更新能够保留可正常工作的安装。
Bug 修复:
增强功能:
测试:
Original summary in English
Summary by Sourcery
Make source deployments atomic and recoverable so interrupted updates preserve a working installation.
Bug Fixes:
Enhancements:
Tests: