115 lines
6.7 KiB
Markdown
115 lines
6.7 KiB
Markdown
# SpacetimeDB publish sccache 降级处理
|
||
|
||
## 背景
|
||
|
||
Windows 本地执行 `npm run dev:rust` 或 `spacetime publish` 时,`spacetime` 会在内部调用 Cargo 构建 `server-rs/crates/spacetime-module`。当前本地开发 publish 会追加 `--build-options="--debug"`,让 SpacetimeDB CLI 用 debug 构建参数编译模块。因为 `server-rs/.cargo/config.toml` 配置了 `rustc-wrapper = "sccache"`,即使当前 shell 没有设置 `RUSTC_WRAPPER`,Cargo 仍会先执行 `sccache rustc -vV`。
|
||
|
||
当本机 sccache server 状态损坏、client/server 通信异常或版本残留不一致时,可能出现:
|
||
|
||
```text
|
||
sccache: error: Timed out waiting for server startup. Maybe the remote service is unreachable?
|
||
sccache: error: failed to execute compile
|
||
sccache: caused by: Failed to send data to or receive data from server
|
||
sccache: caused by: Failed to read response header
|
||
sccache: caused by: failed to fill whole buffer
|
||
```
|
||
|
||
这类错误发生在 rustc wrapper 层,不能说明 SpacetimeDB module 代码本身编译失败。
|
||
|
||
## 2026-05-11 本机根因定位
|
||
|
||
本机 `cargo check -p api-server` 失败时,Cargo 还没有进入业务 crate 编译,而是在读取 `server-rs/.cargo/config.toml` 后执行 `sccache rustc -vV` 探测编译器版本。失败的 stderr 会被写入 `server-rs/target/.rustc_info.json`,内容为 `Timed out waiting for server startup`。
|
||
|
||
当前 PowerShell 环境设置了 `SCCACHE_OSS_BUCKET=genarrative-sccache`、`SCCACHE_OSS_ENDPOINT=https://oss-rg-china-mainland.aliyuncs.com` 和 `SCCACHE_OSS_KEY_PREFIX=genarrative`,且没有设置本地 `SCCACHE_DIR`。因此 sccache daemon 冷启动时会先初始化 OSS 远端缓存,并执行 `.sccache_check` 的读写检查;日志中可见 `Init oss cache ...`、`proxy(http://127.0.0.1:7897/) intercepts ...`,随后才出现 `server started, listening on 127.0.0.1:4226`。
|
||
|
||
本次排查的结论是:冷启动失败主要发生在 sccache client 等待 daemon 启动的握手窗口内,而 daemon 启动又依赖 OSS/本机代理链路先完成缓存可读写检查。代理或 OSS 链路稍慢时,Cargo 调用的 `sccache rustc -vV` 会先超时;daemon 预热后直接执行同一条 `sccache rustc -vV` 又可能成功,所以这是冷启动/通道状态问题,不是 `api-server` 或 Rust 代码错误。
|
||
|
||
辅助证据:
|
||
|
||
1. `rustc -vV` 可直接输出版本,说明 Rust 工具链本身可用。
|
||
2. `tasklist` 曾只看到 `sccache --show-stats` 客户端进程,`netstat` 只出现到 `127.0.0.1:4226` 的 `SYN_SENT`,没有真正的 `LISTEN`,说明当时 client 正在等一个尚未成功监听的 daemon。
|
||
3. 在子进程中临时清掉 `SCCACHE_OSS_*` 并设置本地 `SCCACHE_DIR` 后,sccache 退回本地磁盘缓存,日志显示 `Init disk cache ...`,`rustc -vV` 和 `sccache --show-stats` 均能完成。
|
||
4. `C:\Users\DSK\AppData\Roaming\Mozilla\sccache\config\config` 缺失只是非致命 warning,本机实际配置来自环境变量。
|
||
|
||
## 本地开发处理
|
||
|
||
`scripts/dev-rust-stack.sh` 的 publish 阶段继续由 SpacetimeDB CLI 内部调用 Cargo,并通过 `--build-options="--debug"` 使用 debug 构建参数。遇到 sccache 冷启动超时时,优先保留 `sccache` wrapper,并修复 sccache daemon 的启动等待时间;只有在排除 sccache 本身问题时,才临时绕过 wrapper 验证 rustc 本身可用。
|
||
|
||
该处理不修改 `server-rs/.cargo/config.toml`,也不删除本地 target 缓存。
|
||
|
||
## 手动排障命令
|
||
|
||
优先确认 rustc 本身可用:
|
||
|
||
```bash
|
||
rustc -vV
|
||
```
|
||
|
||
如果要保留 sccache 并修复冷启动等待时间,在 PowerShell 中创建或更新 sccache 默认配置:
|
||
|
||
```powershell
|
||
$configDir = Join-Path $env:APPDATA "Mozilla\sccache\config"
|
||
New-Item -ItemType Directory -Force -Path $configDir | Out-Null
|
||
@(
|
||
"# Windows 本机 sccache 冷启动需要先完成 OSS 缓存读写检查。"
|
||
"# 拉长 client 等待 daemon 启动的时间,避免 Cargo 在 rustc -vV 阶段误判超时。"
|
||
"server_startup_timeout_ms = 60000"
|
||
) | Set-Content -Encoding UTF8 -Path (Join-Path $configDir "config")
|
||
```
|
||
|
||
随后清掉 Cargo 曾缓存的失败探测结果,并从冷启动验证:
|
||
|
||
```powershell
|
||
cd C:\proj\Genarrative\server-rs
|
||
sccache --stop-server
|
||
Remove-Item -Force target\.rustc_info.json -ErrorAction SilentlyContinue
|
||
cargo check -p api-server
|
||
```
|
||
|
||
注意:不要在另一个 `cargo` / `rustc` 仍在编译时执行 `taskkill /F /IM sccache.exe /T`。sccache 对 proc-macro crate 会显示 `Server sent UnhandledCompile` 并把请求转交给真实 rustc;如果此时强杀 sccache client/server,可能让 `serde_derive`、`spacetimedb-bindings-macro` 等 proc-macro 编译直接以 `sccache ... exit code: 1` 失败,而 stderr 里看不到真正的 Rust 诊断。这是排障动作打断编译,不是 `spacetime-module` 源码错误。
|
||
|
||
如果只想临时绕过本次 Cargo 构建的 sccache wrapper,可在 Git Bash 中执行:
|
||
|
||
```bash
|
||
cd server-rs/crates/spacetime-module
|
||
RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo check --target=wasm32-unknown-unknown
|
||
```
|
||
|
||
PowerShell 原生 Cargo 的一次性 wrapper 绕过命令是:
|
||
|
||
```powershell
|
||
cd C:\proj\Genarrative\server-rs
|
||
cargo check -p api-server --config "build.rustc-wrapper=''"
|
||
```
|
||
|
||
如果需要验证是否为 OSS/代理冷启动问题,可只在当前 PowerShell 进程中切到本地缓存做对照:
|
||
|
||
```powershell
|
||
$env:SCCACHE_LOG = "debug"
|
||
$env:SCCACHE_ERROR_LOG = "C:\proj\Genarrative\logs\sccache-local-start-error.log"
|
||
$env:SCCACHE_DIR = Join-Path $env:TEMP "genarrative-sccache-local-test"
|
||
Remove-Item Env:SCCACHE_OSS_BUCKET -ErrorAction SilentlyContinue
|
||
Remove-Item Env:SCCACHE_OSS_ENDPOINT -ErrorAction SilentlyContinue
|
||
Remove-Item Env:SCCACHE_OSS_KEY_PREFIX -ErrorAction SilentlyContinue
|
||
sccache "C:\Users\DSK\.rustup\toolchains\stable-x86_64-pc-windows-msvc\bin\rustc.exe" -vV
|
||
sccache --show-stats
|
||
```
|
||
|
||
如果需要排查 sccache server 状态:
|
||
|
||
```bash
|
||
sccache --show-stats
|
||
sccache --stop-server
|
||
sccache --start-server
|
||
```
|
||
|
||
`sccache --stop-server` 本身也可能因为 server 通道已损坏而失败;只有确认当前没有 `cargo`、`rustc`、`link` 进程后,才用 `taskkill /F /IM sccache.exe /T` 清理残留进程。此时不应阻断本地开发 publish,先使用 wrapper 降级完成验证。
|
||
|
||
## 验证
|
||
|
||
1. `bash -n scripts/dev-rust-stack.sh`
|
||
2. 冷启动后直接执行 `cargo check -p api-server`,确认不再出现 `Timed out waiting for server startup`。
|
||
3. 执行 `cargo check -p spacetime-module`,确认 proc-macro 依赖和 SpacetimeDB module 都能在 sccache wrapper 下通过。
|
||
4. `sccache --show-stats` 显示 `Cache location oss, name: genarrative-sccache`,确认仍在使用 sccache/OSS 缓存。
|
||
5. 重新运行 `npm run dev:rust`,确认 publish 命令带有 `--build-options="--debug"`。
|