From a560e4e6c15346f4c6f0ee3910b1c4fb5a6f1c45 Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 30 Apr 2026 16:54:18 +0800 Subject: [PATCH] Fix dev Rust SpacetimeDB readiness probe --- ...ND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md | 4 ++-- scripts/dev-rust-stack.sh | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md index 100c1d33..d8dff95f 100644 --- a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md +++ b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md @@ -34,7 +34,7 @@ npm run dev:rust 1. 检查 `cargo`、`node` 与 `spacetime` CLI。 2. Windows Git Bash 下如 `server-rs/.spacetimedb/local/bin/current/spacetimedb-cli.exe` 不存在,先把本机 `spacetime` 所在安装目录的 `bin/` 与 `spacetime.exe` 同步到 `server-rs/.spacetimedb/local/`。 3. 启动 `spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101`,确保本地数据库与 SpacetimeDB 内部日志不会落到开发者全局目录。 -4. 等待 `spacetime --root-dir=server-rs/.spacetimedb/local server ping http://127.0.0.1:3101` 可用;判定标准必须包含输出中的 `Server is online:`,不能只依赖 CLI 退出码,因为 SpacetimeDB CLI `2.1.0` 在 `502 Bad Gateway` 时也可能返回退出码 `0`。 +4. 等待 SpacetimeDB 就绪:优先接受 `spacetime --root-dir=server-rs/.spacetimedb/local server ping http://127.0.0.1:3101` 输出中的 `Server is online:`;如果 Windows 下 SpacetimeDB CLI `2.1.0` 对已经监听的 standalone 仍打印 `502 Bad Gateway`,脚本会兜底请求 `http://127.0.0.1:3101/v1/ping`,只有该健康端点返回 `2xx` 时才放行。不能只依赖 CLI 退出码,因为 CLI 在 `502 Bad Gateway` 时也可能返回退出码 `0`。 5. 执行 `spacetime --root-dir=server-rs/.spacetimedb/local publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module -c=on-conflict --yes`,确保 publish 的签名身份与 standalone 的本地控制库一致,并在当前开发阶段允许新版模块表结构变化且发生 schema 冲突时清除旧模块数据。 6. 注入 `GENARRATIVE_API_*` 与 `GENARRATIVE_SPACETIME_*` 后启动 `cargo run -p api-server`;直接运行 `api-server` 时,如未显式设置 `GENARRATIVE_SPACETIME_DATABASE`,服务端也会向上查找 `spacetime.local.json` 作为本地默认库名。 7. 等待 `http://127.0.0.1:/healthz` 返回 HTTP 响应后再启动 Vite,避免前端初始化请求早于 Rust `api-server` 监听完成并在终端刷出 `ECONNREFUSED 127.0.0.1:`。 @@ -103,7 +103,7 @@ npm run dev:rust:logs -- --follow 2. `spacetime --root-dir=server-rs/.spacetimedb/local list --server http://127.0.0.1:3101` 应能看到 `spacetime.local.json` 中的库名;若没有,执行 `spacetime --root-dir=server-rs/.spacetimedb/local publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module -c=on-conflict --yes`。 3. 发布库名与 `GENARRATIVE_SPACETIME_DATABASE` 不一致时,`/api/runtime/custom-world-gallery` 会从 Rust `api-server` 返回 `502`,前端首页只能展示空态或错误提示,无法自行修复。 4. 如果 Vite 输出 `/api/auth/refresh`、`/api/auth/login-options` 或 `/api/runtime/custom-world-gallery` 的 `ECONNREFUSED`,先确认当前脚本是否已经打印 `等待 api-server 就绪` 并通过;正常情况下 Vite 只会在 `/healthz` 可访问后启动,不应再因为 Rust 监听未完成而代理失败。 -5. 如果 `spacetime server ping` 打印 `Server could not be reached (502 Bad Gateway)`,即使命令退出码为 `0` 也必须视为未就绪;脚本会继续等待新启动实例,或在 root-dir 已被其他实例占用时输出占用进程。 +5. 如果 `spacetime server ping` 打印 `Server could not be reached (502 Bad Gateway)`,即使命令退出码为 `0` 也不能直接视为已就绪;本地脚本会继续探测 `/v1/ping`。若 `/v1/ping` 返回 `200`,说明 standalone 已经可用,可以继续发布模块;若 `/v1/ping` 也失败,脚本会继续等待新启动实例,或在 root-dir 已被其他实例占用时输出占用进程。 编译警告治理: diff --git a/scripts/dev-rust-stack.sh b/scripts/dev-rust-stack.sh index 89b1febf..02120232 100644 --- a/scripts/dev-rust-stack.sh +++ b/scripts/dev-rust-stack.sh @@ -96,12 +96,23 @@ is_spacetime_ready() { local root_dir="$2" local output - if ! output="$(spacetime --root-dir="${root_dir}" server ping "${server}" 2>&1)"; then - return 1 + if output="$(spacetime --root-dir="${root_dir}" server ping "${server}" 2>&1)" && + [[ "${output}" == *"Server is online:"* ]]; then + return 0 fi - # SpacetimeDB CLI 2.1.0 在 502 Bad Gateway 时仍可能返回 0,不能只依赖退出码。 - [[ "${output}" == *"Server is online:"* ]] + # SpacetimeDB CLI 2.1.0 在 Windows 下可能对已监听的 standalone 返回 502; + # 直接探测 HTTP 健康端点,避免 npm run dev:rust 卡在“等待 SpacetimeDB 就绪”。 + node -e ' +const target = new URL("/v1/ping", process.argv[1]); +const client = target.protocol === "https:" ? require("https") : require("http"); +const request = client.get(target, { timeout: 1000 }, (response) => { + response.resume(); + process.exit(response.statusCode >= 200 && response.statusCode < 300 ? 0 : 1); +}); +request.on("timeout", () => request.destroy(new Error("timeout"))); +request.on("error", () => process.exit(1)); +' "${server}" >/dev/null 2>&1 } describe_spacetime_root_owner() {