fix deploy spacetime root sync

This commit is contained in:
2026-04-26 23:56:14 +08:00
parent 3198370089
commit 44b08dd51a
5 changed files with 221 additions and 18 deletions

View File

@@ -518,11 +518,12 @@ done
load_env_file "${SCRIPT_DIR}/.env"
load_env_file "${SCRIPT_DIR}/.env.local"
SPACETIME_DATA_DIR="${GENARRATIVE_SPACETIME_DATA_DIR:-${SCRIPT_DIR}/spacetimedb-data}"
SPACETIME_ROOT_DIR="${GENARRATIVE_SPACETIME_ROOT_DIR:-${SCRIPT_DIR}/.spacetimedb}"
SPACETIME_HOST="${GENARRATIVE_SPACETIME_HOST:-__GENARRATIVE_DEFAULT_SPACETIME_HOST__}"
SPACETIME_PORT="${GENARRATIVE_SPACETIME_PORT:-__GENARRATIVE_DEFAULT_SPACETIME_PORT__}"
SPACETIME_SERVER_URL="${GENARRATIVE_SPACETIME_SERVER_URL:-http://${SPACETIME_HOST}:${SPACETIME_PORT}}"
SPACETIME_DATABASE="${GENARRATIVE_SPACETIME_DATABASE:-__GENARRATIVE_DEFAULT_SPACETIME_DATABASE__}"
SPACETIME_TIMEOUT_SECONDS="${GENARRATIVE_SPACETIME_TIMEOUT_SECONDS:-60}"
API_HOST="${GENARRATIVE_API_HOST:-__GENARRATIVE_DEFAULT_API_HOST__}"
API_PORT="${GENARRATIVE_API_PORT:-__GENARRATIVE_DEFAULT_API_PORT__}"
API_LOG="${GENARRATIVE_API_LOG:-info,tower_http=info}"
@@ -543,12 +544,19 @@ require_command() {
}
wait_for_spacetime() {
local deadline=$((SECONDS + 60))
local process_pid="${1:-}"
local deadline=$((SECONDS + SPACETIME_TIMEOUT_SECONDS))
while ((SECONDS < deadline)); do
if spacetime server ping "${SPACETIME_SERVER_URL}" >/dev/null 2>&1; then
if [[ -n "${process_pid}" ]] && ! kill -0 "${process_pid}" 2>/dev/null; then
echo "[start] SpacetimeDB 进程在就绪前退出。" >&2
exit 1
fi
if is_spacetime_ready; then
return
fi
sleep 0.5
done
@@ -556,6 +564,98 @@ wait_for_spacetime() {
exit 1
}
is_spacetime_ready() {
local output
if ! output="$(spacetime --root-dir="${SPACETIME_ROOT_DIR}" server ping "${SPACETIME_SERVER_URL}" 2>&1)"; then
return 1
fi
# SpacetimeDB CLI 2.1.0 在 502 Bad Gateway 时仍可能返回 0不能只依赖退出码。
[[ "${output}" == *"Server is online:"* ]]
}
describe_spacetime_root_owner() {
if command -v ps >/dev/null 2>&1; then
ps -ef 2>/dev/null | grep '[s]pacetime' | grep -F "${SPACETIME_ROOT_DIR}" || true
fi
}
sync_ubuntu_spacetime_install() {
local root_dir="$1"
local target_cli="${root_dir}/bin/current/spacetimedb-cli"
local spacetime_command=""
local resolved_command=""
local install_dir=""
local root_bin="${root_dir}/bin"
local parent_dir=""
local share_bin_dir=""
local version_dir=""
if [[ -x "${target_cli}" ]]; then
return
fi
spacetime_command="$(command -v spacetime || true)"
if [[ -z "${spacetime_command}" ]]; then
echo "[start] 缺少 spacetime 命令,无法同步 SpacetimeDB 安装。" >&2
exit 1
fi
resolved_command="${spacetime_command}"
if command -v readlink >/dev/null 2>&1; then
resolved_command="$(readlink -f "${spacetime_command}" 2>/dev/null || echo "${spacetime_command}")"
fi
install_dir="$(cd -- "$(dirname -- "${resolved_command}")" && pwd)"
mkdir -p "${root_bin}"
for share_bin_dir in \
"/usr/.local/share/spacetime/bin" \
"${HOME:-}/.local/share/spacetime/bin"; do
if [[ -d "${share_bin_dir}" ]]; then
version_dir="$(find "${share_bin_dir}" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)"
if [[ -n "${version_dir}" && -x "${version_dir}/spacetimedb-cli" ]]; then
echo "[start] 同步 Ubuntu SpacetimeDB CLI: ${version_dir}/spacetimedb-cli -> ${target_cli}"
mkdir -p "${root_bin}/current"
cp -f "${version_dir}/spacetimedb-cli" "${target_cli}"
chmod +x "${target_cli}"
return
fi
fi
done
if [[ -d "${install_dir}/bin" ]]; then
echo "[start] 同步 Ubuntu SpacetimeDB 安装: ${install_dir}/bin -> ${root_bin}"
cp -a "${install_dir}/bin/." "${root_bin}/"
elif [[ -x "${install_dir}/current/spacetimedb-cli" ]]; then
echo "[start] 同步 Ubuntu SpacetimeDB 安装: ${install_dir} -> ${root_bin}"
cp -a "${install_dir}/." "${root_bin}/"
elif [[ -x "${install_dir}/spacetimedb-cli" ]]; then
echo "[start] 同步 Ubuntu SpacetimeDB CLI: ${install_dir}/spacetimedb-cli -> ${target_cli}"
mkdir -p "${root_bin}/current"
cp -f "${install_dir}/spacetimedb-cli" "${target_cli}"
chmod +x "${target_cli}"
elif [[ -f "${resolved_command}" ]]; then
parent_dir="$(cd -- "${install_dir}/.." && pwd)"
if [[ -d "${parent_dir}/bin" && -x "${parent_dir}/bin/current/spacetimedb-cli" ]]; then
echo "[start] 同步 Ubuntu SpacetimeDB 安装: ${parent_dir}/bin -> ${root_bin}"
cp -a "${parent_dir}/bin/." "${root_bin}/"
else
echo "[start] 同步 Ubuntu SpacetimeDB 命令: ${resolved_command} -> ${target_cli}"
mkdir -p "${root_bin}/current"
cp -f "${resolved_command}" "${target_cli}"
chmod +x "${target_cli}"
fi
fi
if [[ ! -x "${target_cli}" ]]; then
echo "[start] 同步 SpacetimeDB 安装后仍未找到 ${target_cli}。" >&2
echo "[start] 请确认 Ubuntu 上的 spacetime 安装目录包含 bin/current/spacetimedb-cli或提供可执行的 spacetime 命令。" >&2
exit 1
fi
}
start_process() {
local name="$1"
shift
@@ -575,16 +675,32 @@ start_process() {
require_command node
require_command spacetime
mkdir -p "${PID_DIR}" "${LOG_DIR}" "${SPACETIME_DATA_DIR}"
mkdir -p "${PID_DIR}" "${LOG_DIR}" "${SPACETIME_ROOT_DIR}"
sync_ubuntu_spacetime_install "${SPACETIME_ROOT_DIR}"
start_process spacetimedb \
spacetime \
start \
--data-dir "${SPACETIME_DATA_DIR}" \
--listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}" \
--non-interactive
SPACETIME_PID=""
if is_spacetime_ready; then
echo "[start] 复用已运行的 SpacetimeDB: ${SPACETIME_SERVER_URL}"
else
SPACETIME_ROOT_OWNER="$(describe_spacetime_root_owner)"
if [[ -n "${SPACETIME_ROOT_OWNER}" ]]; then
echo "[start] 当前 root-dir 已被其他 SpacetimeDB 实例占用,无法再次启动。" >&2
echo "[start] 目标地址未就绪: ${SPACETIME_SERVER_URL}" >&2
echo "[start] 如需复用,请把 GENARRATIVE_SPACETIME_PORT 改为占用实例实际端口;如需重启,请先停止下列进程。" >&2
echo "${SPACETIME_ROOT_OWNER}" >&2
exit 1
fi
wait_for_spacetime
start_process spacetimedb \
spacetime \
--root-dir="${SPACETIME_ROOT_DIR}" \
start \
--edition standalone \
--listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"
SPACETIME_PID="$(cat "${PID_DIR}/spacetimedb.pid")"
fi
wait_for_spacetime "${SPACETIME_PID}"
PUBLISH_ARGS=(
publish
@@ -600,7 +716,15 @@ if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
fi
echo "[start] 发布 SpacetimeDB wasm: ${SPACETIME_DATABASE}"
spacetime "${PUBLISH_ARGS[@]}"
if ! spacetime --root-dir="${SPACETIME_ROOT_DIR}" "${PUBLISH_ARGS[@]}"; then
echo "[start] SpacetimeDB 发布失败。" >&2
echo "[start] 如果错误包含 403 Forbidden 或 is not authorized通常是当前 CLI 身份无权更新目标数据库。" >&2
echo "[start] 当前 start.sh 使用的 CLI root: ${SPACETIME_ROOT_DIR}" >&2
spacetime --root-dir="${SPACETIME_ROOT_DIR}" login show >&2 || true
echo "[start] 如果目标是本地库且可以清空数据:先执行 ./stop.sh备份或删除 ${SPACETIME_ROOT_DIR},再重新执行 ./start.sh。" >&2
echo "[start] 如果目标是 Maincloud 或必须保留数据:请切换到创建该数据库的 SpacetimeDB 身份,或把 GENARRATIVE_SPACETIME_DATABASE 改为当前身份有权限的库。" >&2
exit 1
fi
export GENARRATIVE_API_HOST="${API_HOST}"
export GENARRATIVE_API_PORT="${API_PORT}"
@@ -707,7 +831,8 @@ cat >"${TARGET_DIR}/README.md" <<EOF
- \`GENARRATIVE_API_HOST\` / \`GENARRATIVE_API_PORT\` / \`GENARRATIVE_API_LOG\`
- \`GENARRATIVE_SPACETIME_HOST\` / \`GENARRATIVE_SPACETIME_PORT\`
- \`GENARRATIVE_SPACETIME_SERVER_URL\` / \`GENARRATIVE_SPACETIME_DATABASE\`
- \`GENARRATIVE_SPACETIME_DATA_DIR\`
- \`GENARRATIVE_SPACETIME_ROOT_DIR\`:默认使用发布目录下的 \`.spacetimedb/\`,同时承载本地 SpacetimeDB 运行数据与 CLI 身份。
- \`GENARRATIVE_SPACETIME_TIMEOUT_SECONDS\`:等待 SpacetimeDB 就绪的秒数,默认 \`60\`。
- OSS、LLM、短信、微信等业务密钥仍通过目标服务器环境变量或同目录 \`.env.local\` 管理。
EOF