diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index be23148d..f0dfdc3c 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -201,7 +201,7 @@ UI 相关修改要重点验证: npm run database:backup:oss -- --data-dir /stdb --stop-service spacetimedb.service ``` -脚本会将数据目录打包成 `tar.gz`,上传到 `oss://///-.tar.gz`。生产建议做冷备份:传入 `--stop-service spacetimedb.service`,脚本会在打包前停止服务、打包后恢复服务,再上传 OSS。由于 OSS 上传可能受服务器带宽限制,`Genarrative-Stdb-Module-Publish` 默认使用 `DATABASE_BACKUP_MODE=async`:先在 publish 前用 `--defer-upload` 生成本地冷备份和 `.manifest.json`,随后继续执行 publish;发布脚本退出前会用后台 `node ... --upload-archive ` 上传同一份发布前备份,不等待上传完成。需要强一致发布闸门时改用 `DATABASE_BACKUP_MODE=sync`(等价脚本参数 `--backup-mode sync`),备份会在 publish 前同步打包并上传,失败会阻断 publish;确认已有其他备份窗口时才使用 `DATABASE_BACKUP_MODE=skip`(兼容脚本参数 `--skip-backup`)。若业务不能接受停机窗口,应先规划 SpacetimeDB 原生快照或主备策略,不要直接在写入中的数据目录上做热拷贝并当作强一致备份。 +脚本会将数据目录打包成 `tar.gz`,上传到 `oss://///-.tar.gz`。生产建议做冷备份:传入 `--stop-service spacetimedb.service`,脚本会在打包前停止服务、打包后恢复服务,再上传 OSS。由于 OSS 上传可能受服务器带宽限制,`Genarrative-Stdb-Module-Publish` 默认使用 `DATABASE_BACKUP_MODE=async`:先在 publish 前用 `--defer-upload` 生成本地冷备份和 `.manifest.json`,随后继续执行 publish;发布脚本退出前会用后台 `node ... --upload-archive ` 上传同一份发布前备份,不等待上传完成。发布脚本在校验 wasm 后、执行 `spacetime publish` 前会等待显式 `SPACETIME_SERVER_URL` 的 `/v1/ping` 就绪,默认最多等待 `60` 秒;如生产机器冷备份恢复 `spacetimedb.service` 较慢,可临时设置 `GENARRATIVE_STDB_PUBLISH_READY_TIMEOUT_SECONDS` 调整等待时间。需要强一致发布闸门时改用 `DATABASE_BACKUP_MODE=sync`(等价脚本参数 `--backup-mode sync`),备份会在 publish 前同步打包并上传,失败会阻断 publish;确认已有其他备份窗口时才使用 `DATABASE_BACKUP_MODE=skip`(兼容脚本参数 `--skip-backup`)。若业务不能接受停机窗口,应先规划 SpacetimeDB 原生快照或主备策略,不要直接在写入中的数据目录上做热拷贝并当作强一致备份。 生产环境变量模板在 `deploy/env/api-server.env.example`: diff --git a/scripts/deploy/production-stdb-publish.sh b/scripts/deploy/production-stdb-publish.sh index 21b4e68f..64f4e9dd 100644 --- a/scripts/deploy/production-stdb-publish.sh +++ b/scripts/deploy/production-stdb-publish.sh @@ -53,6 +53,7 @@ ASYNC_BACKUP_SCRIPT="" ASYNC_BACKUP_ARCHIVE="" ASYNC_BACKUP_MANIFEST="" ASYNC_BACKUP_LOG="" +SPACETIME_READY_TIMEOUT_SECONDS="${GENARRATIVE_STDB_PUBLISH_READY_TIMEOUT_SECONDS:-60}" while [[ $# -gt 0 ]]; do case "$1" in @@ -128,6 +129,11 @@ if [[ -n "${RUN_AS_USER}" && ! "${RUN_AS_USER}" =~ ^[A-Za-z_][A-Za-z0-9_-]*$ ]]; exit 1 fi +if [[ ! "${SPACETIME_READY_TIMEOUT_SECONDS}" =~ ^[0-9]+$ || "${SPACETIME_READY_TIMEOUT_SECONDS}" -le 0 ]]; then + echo "[production-stdb-publish] GENARRATIVE_STDB_PUBLISH_READY_TIMEOUT_SECONDS 必须是正整数: ${SPACETIME_READY_TIMEOUT_SECONDS}" >&2 + exit 1 +fi + if [[ ! -d "${SOURCE_DIR}" ]]; then echo "[production-stdb-publish] 发布目录不存在: ${SOURCE_DIR}" >&2 exit 1 @@ -203,6 +209,33 @@ start_async_backup_upload() { ASYNC_BACKUP_STATUS_FILE="" } +wait_for_spacetime_ready() { + if [[ -z "${SERVER_URL}" ]]; then + echo "[production-stdb-publish] 使用 server alias=${SERVER_ALIAS},跳过 URL 健康检查等待" + return 0 + fi + + local ping_url="${SERVER_URL%/}/v1/ping" + local deadline=$((SECONDS + SPACETIME_READY_TIMEOUT_SECONDS)) + local last_status="" + + echo "[production-stdb-publish] 等待 SpacetimeDB 就绪: ${ping_url},timeout=${SPACETIME_READY_TIMEOUT_SECONDS}s" + while (( SECONDS < deadline )); do + # curl 失败时通常表示服务尚未监听;不立即失败,等待冷备份恢复后的 systemd 启动完成。 + if last_status="$(curl -fsS --max-time 2 "${ping_url}" 2>&1)"; then + echo "[production-stdb-publish] SpacetimeDB 已就绪: ${ping_url}" + return 0 + fi + sleep 2 + done + + echo "[production-stdb-publish] SpacetimeDB 未在超时内就绪: ${ping_url}" >&2 + if [[ -n "${last_status}" ]]; then + echo "[production-stdb-publish] 最后一次健康检查输出: ${last_status}" >&2 + fi + return 1 +} + "${SCRIPT_DIR}/maintenance-on.sh" "spacetime module publish ${DATABASE}" case "${BACKUP_MODE}" in @@ -237,6 +270,8 @@ echo "[production-stdb-publish] 校验 wasm" sha256sum -c spacetime_module.wasm.sha256 ) +wait_for_spacetime_ready + PUBLISH_ARGS=( --root-dir="${SPACETIME_ROOT_DIR}" publish