From 136756134a3d12224cad5fba33e274dfb6454840 Mon Sep 17 00:00:00 2001 From: Linghong Date: Mon, 14 Sep 2026 06:19:38 +0000 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E6=98=BE=E5=BC=8F=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=20Windows=20sccache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 未配置 wrapper 时默认回退到直接 rustc 处理 sccache 探测失败与 wrapper 配置冲突 同步更新开发运维和排障文档 --- docs/project-memory/shared-memory/pitfalls.md | 4 +- ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 +- scripts/dev.mjs | 36 ++++++++++++------ scripts/dev.test.ts | 37 +++++++++++++++++-- 4 files changed, 62 insertions(+), 17 deletions(-) diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 230c06b9d..9e6d2aad7 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -1158,8 +1158,8 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - 现象:Windows 上执行 `npm run dev:api-server` 时,api-server 在 Cargo 启动阶段失败,日志出现 `error: multiple input filenames provided (first two filenames are ... rustc.exe and -)`,`/healthz` 无法访问。 - 原因:`server-rs/.cargo/config.toml` 默认配置 `rustc-wrapper = "sccache"`;本地 dev 脚本为了绕过损坏的 sccache 需要覆盖 wrapper。Windows 下如果把 `RUSTC_WRAPPER` 设置为 `rustc`,Cargo 会按 wrapper 协议调用 `rustc <真实rustc路径> - ...`,真实 rustc 把 wrapper 传入的 rustc 路径和 stdin `-` 都当输入文件。 -- 处理:Windows 本地 dev 脚本应把 `RUSTC_WRAPPER` 和 `CARGO_BUILD_RUSTC_WRAPPER` 显式设为空字符串,让 Cargo 覆盖项目配置并直连真实 rustc;Linux 保持 `/usr/bin/env` 绕过 sccache。 -- 验证:`npm run test -- scripts/dev.test.ts -t "Windows 下本地 dev Rust env 用空 wrapper 覆盖项目 sccache"`,并用 `npm run dev:api-server` 拉起后访问实际 api 端口的 `/healthz` 返回 200。 +- 处理:Windows 本地 dev 脚本默认把两个 wrapper 设为空字符串;只有用户显式配置 `RUSTC_WRAPPER` 或 `CARGO_BUILD_RUSTC_WRAPPER` 时才处理 sccache。sccache 配置会先限时执行真实 `sccache rustc -vV` 探测,失败、超时或两个变量冲突时回退到直接 rustc;Linux 保持 `/usr/bin/env` 绕过 sccache。 +- 验证:`npm run test -- scripts/dev.test.ts -t "dev scheduler Rust build env"`,并用 `npm run dev:api-server` 拉起后访问实际 api 端口的 `/healthz` 返回 200。 - 关联:`scripts/dev.mjs`、`scripts/dev.test.ts`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 ## Pingora 直连 80/443 不能只改 env diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index dea400b84..1e9d54d60 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -66,7 +66,7 @@ AI 游戏创作客户端使用 `npm run agc`。该入口由 `apps/ai-game-creato Tauri `beforeDevCommand` 默认与客户端构建并行,不能把上述检查只放在 `beforeDevCommand` 内:选定地址上若已有旧 Vite,Tauri 可能先创建加载旧前端的窗口,随后配套后端才因代理不匹配退出。外层启动器会把 Tauri CLI 放入受控进程树;CLI 正常退出、启动失败或收到终止信号后,POSIX 先向保留的 PGID 发送 `SIGTERM`、有界等待后升级 `SIGKILL`,Windows 使用 `taskkill /PID /T /F`。Windows 下每个长驻服务都经 `cmd.exe /d /s /c` 包装层启动,Ctrl+C 会先杀掉包装层(退出码 `0xC000013A`),因此清理不能只看直接子进程是否存活:`taskkill` 对已退出的 PID 只会失败,必须继续按记录下来的根 PID 遍历,并在退出时按本工作树 `api-server.exe` 绝对路径(以及本次自己拉起的 SpacetimeDB `--data-dir`)做一次身份兜底清扫;`scripts/dev-windows-process.mjs` 是这套判定的唯一实现。Linux 容器中的孤儿后代退出后可能暂时保留为 zombie,`kill(-PGID, 0)` 仍会返回成功;启动器必须结合 `/proc//stat` 判断同组是否还存在非 zombie 成员,不能把等待 PID 1 回收误报为清理失败。配套后端和 Vite 仍由 `start-dev-stack.mjs` 各自持有,退出时同样有界收束,避免只剩客户端、Runner、Cargo 或旧订阅进程。排障时同时核对控制台输出的 AGC Vite 实际地址及其 marker、`.app/dev-stack.json` 的实际 API URL 和进程 cwd;不要把“终端已返回”当成客户端及其 Runner 已退出的证据。 -Windows 本地 `npm run dev` / `npm run dev:api-server` / `npm run dev:bgfilter-worker` 会先探测 `sccache --version`:可用时设置 `RUSTC_WRAPPER` / `CARGO_BUILD_RUSTC_WRAPPER=sccache` 使用缓存;未安装或不可执行时设置为空值覆盖 `server-rs/.cargo/config.toml`,回退到真实 `rustc`,不阻断启动。完整栈和 `dev:api-server` 把 API 与 BgFilter worker 作为一个 Rust 重启单元:源码变化时先停两个进程,再先启动并验活 worker、最后启动并验活 API,避免两个 `cargo run` 并发链接同一个 Windows 可执行文件。不要把 wrapper 绕过值写成 `rustc`;Cargo 会按 wrapper 协议调用 `rustc <真实rustc路径> - ...`,最终报 `multiple input filenames provided` 并导致 api-server 无法启动。排查本地启动失败时,先看 dev 日志中的 sccache 启用或回退提示。 +Windows 本地 `npm run dev` / `npm run dev:api-server` / `npm run dev:bgfilter-worker` 默认不主动启用 sccache;只有用户通过 `RUSTC_WRAPPER` 或 `CARGO_BUILD_RUSTC_WRAPPER` 显式配置 wrapper 时才进入处理流程。配置为 sccache 时会限时执行真实 wrapper 探测,成功才使用缓存;未安装、不可执行、超时或两个变量冲突时设置为空值,回退到真实 `rustc`,不阻断启动。完整栈和 `dev:api-server` 把 API 与 BgFilter worker 作为一个 Rust 重启单元:源码变化时先停两个进程,再先启动并验活 worker、最后启动并验活 API,避免两个 `cargo run` 并发链接同一个 Windows 可执行文件。不要把 wrapper 绕过值写成 `rustc`;Cargo 会按 wrapper 协议调用 `rustc <真实rustc路径> - ...`,最终报 `multiple input filenames provided` 并导致 api-server 无法启动。排查本地启动失败时,先看 dev 日志中的 wrapper 启用、冲突或回退提示。 ### 本地 Rust 构建缓存与磁盘上限 diff --git a/scripts/dev.mjs b/scripts/dev.mjs index dfba21bc6..a1aefc2f3 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -591,23 +591,37 @@ function buildLocalRustProcessEnv(env, options = {}) { String(mergedEnv.RUSTC_WRAPPER ?? '').trim(), String(mergedEnv.CARGO_BUILD_RUSTC_WRAPPER ?? '').trim(), ].filter(Boolean); - const customWrapper = wrappers.find( - (wrapper) => !isSccacheRustcWrapper(wrapper), - ); - if (customWrapper) { - mergedEnv.RUSTC_WRAPPER = customWrapper; - mergedEnv.CARGO_BUILD_RUSTC_WRAPPER = customWrapper; + const uniqueWrappers = [...new Set(wrappers)]; + if (uniqueWrappers.length > 1) { + mergedEnv.RUSTC_WRAPPER = ''; + mergedEnv.CARGO_BUILD_RUSTC_WRAPPER = ''; + if (options.log !== false) { + console.warn( + '[dev:rust] RUSTC_WRAPPER 与 CARGO_BUILD_RUSTC_WRAPPER 配置冲突,回退到直接 rustc。', + ); + } return mergedEnv; } - const rustcWrapperBypass = resolveLocalDevRustcWrapperBypass(options); - mergedEnv.RUSTC_WRAPPER = rustcWrapperBypass; - mergedEnv.CARGO_BUILD_RUSTC_WRAPPER = rustcWrapperBypass; + const configuredWrapper = uniqueWrappers[0] ?? ''; + if (configuredWrapper && !isSccacheRustcWrapper(configuredWrapper)) { + mergedEnv.RUSTC_WRAPPER = configuredWrapper; + mergedEnv.CARGO_BUILD_RUSTC_WRAPPER = configuredWrapper; + return mergedEnv; + } + + const rustcWrapper = configuredWrapper + ? resolveLocalDevRustcWrapperBypass(options) + : ''; + mergedEnv.RUSTC_WRAPPER = rustcWrapper; + mergedEnv.CARGO_BUILD_RUSTC_WRAPPER = rustcWrapper; if (options.log !== false) { console.warn( - rustcWrapperBypass + rustcWrapper ? '[dev:rust] 本地 dev 构建启用 sccache wrapper。' - : '[dev:rust] 本地 dev 构建未找到可用 sccache,回退到直接 rustc。', + : configuredWrapper + ? '[dev:rust] sccache wrapper 探测失败,回退到直接 rustc。' + : '[dev:rust] 未显式配置 Rust wrapper,使用直接 rustc。', ); } return mergedEnv; diff --git a/scripts/dev.test.ts b/scripts/dev.test.ts index 4bf5cc82d..e7449cb5f 100644 --- a/scripts/dev.test.ts +++ b/scripts/dev.test.ts @@ -657,6 +657,28 @@ describe('dev scheduler local worker cleanup', () => { }); describe('dev scheduler Rust build env', () => { + test('Windows 下未显式配置 wrapper 时默认关闭 sccache', () => { + const originalPlatform = Object.getOwnPropertyDescriptor( + process, + 'platform', + ); + Object.defineProperty(process, 'platform', { + configurable: true, + value: 'win32', + }); + try { + const env = buildLocalRustProcessEnv( + {}, + { log: false, sccacheAvailable: true }, + ); + expect(env.RUSTC_WRAPPER).toBe(''); + expect(env.CARGO_BUILD_RUSTC_WRAPPER).toBe(''); + } finally { + if (originalPlatform) + Object.defineProperty(process, 'platform', originalPlatform); + } + }); + test('local dev Rust env enables available sccache wrapper', () => { const originalPlatform = Object.getOwnPropertyDescriptor( process, @@ -670,7 +692,7 @@ describe('dev scheduler Rust build env', () => { try { const env = buildLocalRustProcessEnv( { - RUSTC_WRAPPER: '/usr/bin/sccache', + RUSTC_WRAPPER: 'sccache', CARGO_BUILD_RUSTC_WRAPPER: 'sccache', }, { log: false, sccacheAvailable: true }, @@ -685,11 +707,11 @@ describe('dev scheduler Rust build env', () => { } }); - test('local dev Rust env keeps healthy custom wrapper untouched', () => { + test('Rust wrapper 配置为同一个自定义 wrapper 时保持不变', () => { const env = buildLocalRustProcessEnv( { RUSTC_WRAPPER: 'custom-wrapper', - CARGO_BUILD_RUSTC_WRAPPER: 'sccache', + CARGO_BUILD_RUSTC_WRAPPER: 'custom-wrapper', }, { log: false }, ); @@ -725,6 +747,15 @@ describe('dev scheduler Rust build env', () => { } } }); + + test('Rust wrapper 配置冲突时回退到空 wrapper', () => { + const env = buildLocalRustProcessEnv( + { RUSTC_WRAPPER: 'sccache', CARGO_BUILD_RUSTC_WRAPPER: 'custom-wrapper' }, + { log: false }, + ); + expect(env.RUSTC_WRAPPER).toBe(''); + expect(env.CARGO_BUILD_RUSTC_WRAPPER).toBe(''); + }); }); describe('dev scheduler stack state file', () => {