Repository navigation
fix: 修复 uv 成功退出后仍被报错的问题 (T5.18) #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jinghero
merged 4 commits into
AUTO-MAS-Project:main
from
jinghero:fix/uv-startup-readable-20261112
Nov 12, 2026
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # T5.18 实施计划 | ||
|
|
||
| 1. 在 `internal/uv/runner_isolation_windows_test.go` 固定短进程已退出的原生 API 顺序,并从实际 `UVRunner.Run` 的 Job 边界复现错误。固定测试名为 `TestRunner_ExitedProcessCannotJoinJob`、`TestRunner_AssignsBeforeExecuting`。基线执行 `go test ./internal/uv -run 'TestRunner_(ExitedProcessCannotJoinJob|AssignsBeforeExecuting)$' -v -count=1`,前者通过,后者因子进程已退出、隔离失败而失败。 | ||
| 2. 在 `internal/uv/runner_windows.go` 挂起创建,`internal/uv/runner.go` 分配后恢复,`internal/process/managed_windows.go` 复用现有恢复线程实现;保留非 Windows 编译边界。补恢复前取消验证,复用现有执行器检查。 | ||
| 3. 运行 gofmt、vet、build、完整测试、protocol 100 轮和可用时的 race,复核真实 uv 探针。按实际结果更新设计;提交时显式暂存本任务源码、测试和文档,不改其他在途任务。代码与进度分别提交。提交后独立复核,不合入或推送其他分支。 | ||
|
|
||
| 4. PR #37 复审补充:固定 `Run` 通过取消检查后、恢复线程前发生取消或 deadline 的真实 Windows 顺序。只在恢复进程的 OS 调用处增加私有函数字段,默认调用既有 `process.ResumeSuspended`;不 mock `Run`、取消检查或错误分类。固定测试名 `TestRunner_ResumeFailurePreservesCancellation`,同时覆盖未取消的真实恢复失败,断言协议类别、真实进程退出及原始/清理错误链。先红后绿,复用 uv 全包和相关共享进程检查,不重跑已经明确受本机环境影响的全量与 race。 |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # T5.18 短命 uv 进程纳管 | ||
|
|
||
| ## 问题与证据 | ||
|
|
||
| `UVRunner.Run` 原先先执行 `command.Start()`,再创建 Job 并按 PID 分配。Windows 原生检查固定子进程成功退出、父进程尚未 `Wait` 的顺序后,`OpenProcess` 成功、`WaitForSingleObject` 返回 `WAIT_OBJECT_0`、退出码为 0,而 `AssignProcessToJobObject` 返回 `ERROR_ACCESS_DENIED (5)`。在实际 `UVRunner.Run` 的 Job 边界延后 Assign,同样把成功的版本探针报告为 `uv.verify` 隔离失败。 | ||
|
|
||
| 这确认了短进程退出早于 Assign 的竞态。用户原始日志只有 `process_isolation_failed`,没有失败 API 或 Windows 错误号,不能据此断言用户现场必为本竞态。v0.1.24、v0.1.28、v0.1.29 的执行顺序相同,本问题并非 v0.1.29 新引入。 | ||
|
|
||
| ## 方案与边界 | ||
|
|
||
| 一次性 uv 同长驻进程一样以 `CREATE_SUSPENDED | CREATE_NO_WINDOW` 创建。Job 分配成功后才恢复初始线程;恢复逻辑复用 `process` 现有线程查找、恢复和句柄关闭实现。`UVRunner` 继续拥有 `exec.Cmd`、原始双流管道、输出上限、逐行回调、Wait 和取消,不改为 `ManagedProcess`,避免改变一次性命令的输出及退出码语义。 | ||
|
|
||
| Job 创建、分配、线程恢复任一步失败均结束并等待本次进程,保留真实错误,不恢复未纳管进程。取消在恢复前再次检查,取消不允许子进程开始业务工作。恢复阶段的本地诊断沿用已有隔离诊断,操作名为 `resume_process`;不新增协议字段,不改变错误码四元组,不影响宿主控制台或网络策略。 | ||
|
|
||
| ## 验收 | ||
|
|
||
| 实际 Windows API 检查保留已退出进程分配失败的证据;实际 `UVRunner` 检查在 Assign 前进程尚未执行、恢复后双流输出完整且退出码正确。复用已有非零退出、回调失败、输出上限、超时、取消和进程树测试,新增恢复前取消检查。检查使用进程信号和有界等待,不以 sleep 安排顺序。 | ||
|
|
||
| ## 本地验收,2026-11-12 | ||
|
|
||
| 环境为 Windows amd64、Go 1.26.11。检查源码与 `v0.1.24`、`v0.1.28`、`v0.1.29`,历史执行器和 Job 文件在这些 tag 间无差异。以下命令均在独立 worktree 执行,原始开机/休眠现场未复测。 | ||
|
|
||
| - `go test ./internal/uv -run 'TestRunner_(ExitedProcessCannotJoinJob|AssignsBeforeExecuting)$' -v -count=1`:原始执行器通过 Go overlay 复跑退出 1,日志给出原生 API 错误 5 和成功退出码 0;修改后退出 0,Assign 前为 `WAIT_TIMEOUT` / `STILL_ACTIVE`,随后双流输出完整、退出码 0。 | ||
| - `go test ./internal/uv -run 'TestRunner_(ExitedProcessCannotJoinJob|AssignsBeforeExecuting|CancelBeforeResumeDoesNotExecute)$' -v -count=100`:退出 0。`go test ./internal/uv -run '^TestRunner_CancelReapsDescendants$' -v -count=20`:退出 0,取消后通过原生进程句柄确认后代退出。 | ||
| - 作者隔离探针用同一真实 `UVRunner.Run` 执行固定 uv 0.12.3 和本机 uv 0.13.7 的 `--version`。在 Assign 边界等待快进程退出时,原始执行器均退出 1、报告隔离失败;修改后均有完整真实版本输出、退出码 0。探针和原始源码 overlay 留在本地证据目录,没有加入默认测试或修改安装版。 | ||
| - `go test ./internal/uv -count=1` 退出 0;执行器、原有 Job、M5 事务定向检查退出 0,覆盖非零退出、无窗口、参数、双流、输出边界、回调失败、取消和进程树回收。定向检查明确排除了下面已经在基线复现的 breakaway 夹具。 | ||
| - `gofmt -l .` 无输出;`go vet ./...`、`go build -buildvcs=false ./...`、`git diff --check` 均退出 0;`go test ./internal/protocol -count=100` 退出 0。 | ||
| - 完整 `go test ./... -count=1` 退出 1:`lock` 的 SUBST W: 未就绪、`process` 的 breakaway 孙进程不属于任何 Job 断言失败,均在未修改源码的定向检查中复现。另有 `cli` 的 TempDir 清理偶发目录非空,原始执行器定向十轮和修改后定向均通过,未归因于本改动。其余包通过,不能表述为完整门禁通过。 | ||
| - `go test -race ./... -count=1` 退出 2,提示需要 cgo。本机 `CGO_ENABLED=0` 且 PATH 无 GCC,race 未执行,仍需在具备工具链的 Windows 环境验证。 | ||
|
|
||
| 本次只复用既有结构化错误、本地诊断和 Sentry 结果归属;`resume_process` 为现有 operation 字段的稳定值,不新增采集字段。主仓恢复修复可以独立交付,不依赖本 Runtime 的未发布制品。 | ||
|
|
||
| 实际证据文件包括 `isolation-baseline-final.log`、`relevant-tests-final.log`、`isolation-repeat.log`、`descendant-cancel.log`、`uv0123-baseline.log`、`uv0123-fixed.log`、`full-tests.log`、`breakaway-baseline.log`、`subst-unmodified.log`、`race.log`。用户现场仍需使用发布后的 Runtime 收集具体失败 API 和 Windows 错误号,才能判断是否同一原因。 | ||
|
|
||
| 复审发现恢复前取消和恢复失败的新增分支丢弃了清理错误,现用既有错误链保留 Kill、Wait、Job.Close 和原始原因。`TestRunner_CancelBeforeResumePreservesCleanupError` 在修正前失败、修正后通过;真实 Job 纳管后取消,并在实际关闭后注入清理错误,确认取消与清理原因均可追溯。修正后的完整 uv 包、vet 和 build 再次通过。 | ||
|
|
||
| ## PR #37 恢复期间取消分类复审 | ||
|
|
||
| [P2 审查](https://github.com/AUTO-MAS-Project/AUTO-MAS-Runtime/pull/37#discussion_r4549513344) 指出取消检查和线程恢复之间的窗口。Windows 原生复现确认:`Run` 已通过取消检查,随后用户取消或真实 context deadline 到达,`CommandContext` watcher 结束挂起进程;此时真实 `ResumeSuspended` 找不到初始线程。原实现仅保留恢复和清理错误,返回 `UV_EXEC_FAILED` / 50,没有保留 context 错误。 | ||
|
|
||
| 修正仅在恢复失败、完成本次 Kill/Wait/Job.Close 后重新检查 `ctx.Err()`,将取消与原始恢复和清理原因放入同一错误链,沿用已有 `OPERATION_CANCELLED` / 130 契约。未取消的真实恢复失败仍为隔离错误,不吞掉 API 错误,不改变协议、版本或重试策略。正常完成路径原本已经优先检查 `ctx.Err()`,本次使恢复失败路径遵守同一规则。 | ||
|
|
||
| 检查只在实际恢复进程的 OS 调用处提供与 `newJob` 同级的私有函数字段,默认仍调用 `process.ResumeSuspended`。`TestRunner_ResumeFailurePreservesCancellation` 执行真实生产 `Run`、Windows Job、`CommandContext` 和线程恢复;故障时序安排在通过取消检查后的恢复边界,不替换编排或分类。取消和真实 5 秒 deadline 两项等待实际进程句柄已收到退出信号后调用真实恢复,未取消对照则由外部终止挂起进程。三项均核对从未执行业务、进程已退出,以及原始恢复、真实 Wait 和实际 Job 关闭后的清理错误仍在链中。 | ||
|
|
||
| 验证基线为 `1ef8ac3ce0469fdb1c4c580d7052258d7a69cba8`。`go test ./internal/uv -run '^TestRunner_ResumeFailurePreservesCancellation$' -v -count=1` 修正前退出 1,取消和 deadline 错报 50,对照通过;修正后退出 0,分别为 130、130、50。`go test ./internal/uv -run '^TestRunner_ResumeFailurePreservesCancellation$/(cancel|uncancelled)$' -v -count=100` 退出 0。 | ||
|
|
||
| `go test ./internal/uv -count=1`、共享进程挂起/分配/恢复失败/取消/空树/后代回收定向检查、CLI 取消错误链映射与最终 NDJSON 取消状态/退出码 130 检查均退出 0。`gofmt -l .` 无输出,`go vet ./...`、`go build -buildvcs=false ./...`、`git diff --check` 退出 0。本轮没有重跑已知受本机环境限制的完整测试或不可用的 race,不增加这些检查已通过的结论。原始命令输出位于本地 `review-followup-runtime` 证据目录。 |
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
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
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
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
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.