From a052494eed83fde2d0667a63b7ba224b1a5b8f9c Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Mon, 1 Jun 2026 17:28:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=AE=A2=E6=88=B7=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E5=85=A5=E5=8F=A3=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/deployment/部署说明.md | 2 +- .../__tests__/smoke-install-script.test.ts | 2 ++ scripts/smoke-install.ps1 | 28 ++++++++++++++++--- scripts/smoke-install.sh | 25 +++++++++++++---- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/docs/deployment/部署说明.md b/docs/deployment/部署说明.md index 28bff88..f329ecb 100644 --- a/docs/deployment/部署说明.md +++ b/docs/deployment/部署说明.md @@ -347,7 +347,7 @@ Windows 实施机或已安装 PowerShell 的现场,可以使用对应 `.ps1` .\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" ``` -这些脚本会先做安装前检查,再检查 Compose 配置、容器状态、应用运行镜像、镜像内版本文件、Prisma 迁移状态、MinIO bucket 和 `/api/health`。建议每次首装或升级验收都带上期望版本,`.sh` 使用 `--expect-version x.x.x`,`.ps1` 使用 `-ExpectedVersion x.x.x`,这样现场可以直接确认运行的就是本次交付版本。如果客户使用外部对象存储,`.sh` 脚本加 `--skip-object-storage-check`,`.ps1` 脚本加 `-SkipObjectStorageCheck`,对象存储验收按客户现场方案单独执行。 +这些脚本会先做安装前检查,再检查 Compose 配置、容器状态、应用运行镜像、镜像内版本文件、Prisma 迁移状态、MinIO bucket 和 `/api/health`。建议每次首装或升级验收都带上期望版本,`.sh` 使用 `--expect-version x.x.x`,`.ps1` 使用 `-ExpectedVersion x.x.x`,脚本会同时确认容器内 `VERSION.txt` 和浏览器访问入口 `/api/health` 返回的版本,避免现场访问地址指到旧服务。如果客户使用外部对象存储,`.sh` 脚本加 `--skip-object-storage-check`,`.ps1` 脚本加 `-SkipObjectStorageCheck`,对象存储验收按客户现场方案单独执行。 人工验收命令仍保留如下: diff --git a/scripts/__tests__/smoke-install-script.test.ts b/scripts/__tests__/smoke-install-script.test.ts index f20713d..0afe877 100644 --- a/scripts/__tests__/smoke-install-script.test.ts +++ b/scripts/__tests__/smoke-install-script.test.ts @@ -32,6 +32,8 @@ describe('scripts/smoke-install.ps1', () => { expect(script).toContain('cat VERSION.txt') expect(script).toContain('[string]$ExpectedVersion = ""') expect(script).toContain('应用版本符合预期') + expect(script).toContain('/api/health 正常,版本符合预期') + expect(script).toContain('没有返回期望版本') expect(script).toContain('npx", "prisma", "migrate", "status"') expect(script).toContain('/api/health') }) diff --git a/scripts/smoke-install.ps1 b/scripts/smoke-install.ps1 index b6c2f9d..9389765 100644 --- a/scripts/smoke-install.ps1 +++ b/scripts/smoke-install.ps1 @@ -273,21 +273,41 @@ function Get-ServiceContainerId { } function Wait-Health { - param([string]$HealthUrl, [int]$TimeoutSeconds) + param([string]$HealthUrl, [int]$TimeoutSeconds, [string]$ExpectedVersion = "") $deadline = (Get-Date).AddSeconds($TimeoutSeconds) + $lastVersion = "" do { try { $response = Invoke-WebRequest -Uri $HealthUrl -UseBasicParsing -TimeoutSec 10 if ($response.StatusCode -eq 200) { - Write-Ok "/api/health 正常" - return + if ([string]::IsNullOrWhiteSpace($ExpectedVersion)) { + Write-Ok "/api/health 正常" + return + } + + try { + $healthData = $response.Content | ConvertFrom-Json + $lastVersion = "$($healthData.version)".Trim() + } catch { + $lastVersion = "" + } + + if ($lastVersion -eq $ExpectedVersion) { + Write-Ok "/api/health 正常,版本符合预期:$ExpectedVersion" + return + } } } catch { Start-Sleep -Seconds 5 } } while ((Get-Date) -lt $deadline) + if (-not [string]::IsNullOrWhiteSpace($ExpectedVersion)) { + $actual = if ([string]::IsNullOrWhiteSpace($lastVersion)) { "未返回" } else { $lastVersion } + throw "/api/health 在 $TimeoutSeconds 秒内没有返回期望版本:实际 $actual,预期 $ExpectedVersion" + } + throw "/api/health 在 $TimeoutSeconds 秒内没有通过:$HealthUrl" } @@ -374,7 +394,7 @@ try { throw "未配置 APP_PUBLIC_URL / NEXTAUTH_URL,无法验收健康接口。" } - Wait-Health -HealthUrl ($publicUrl.TrimEnd("/") + "/api/health") -TimeoutSeconds $HealthTimeoutSeconds + Wait-Health -HealthUrl ($publicUrl.TrimEnd("/") + "/api/health") -TimeoutSeconds $HealthTimeoutSeconds -ExpectedVersion $ExpectedVersion if (-not $SkipMigrationStatus) { Write-Info "检查数据库迁移状态" diff --git a/scripts/smoke-install.sh b/scripts/smoke-install.sh index 917800c..a1f5d04 100644 --- a/scripts/smoke-install.sh +++ b/scripts/smoke-install.sh @@ -330,15 +330,30 @@ wait_service_running() { wait_health() { local health_url="$1" local timeout="$2" - local deadline + local expected_version="${3:-}" + local deadline body + local last_version="" deadline=$(( $(date +%s) + timeout )) while [[ "$(date +%s)" -le "$deadline" ]]; do - if curl -fsS "$health_url" >/dev/null 2>&1; then - ok "/api/health 正常" - return 0 + if body="$(curl -fsS "$health_url" 2>/dev/null)"; then + if [[ -z "$expected_version" ]]; then + ok "/api/health 正常" + return 0 + fi + last_version="$(printf '%s' "$body" | sed -nE 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' | head -n 1)" + if [[ "$last_version" == "$expected_version" ]]; then + ok "/api/health 正常,版本符合预期:$expected_version" + return 0 + fi fi sleep 5 done + + if [[ -n "$expected_version" ]]; then + [[ -n "$last_version" ]] || last_version="未返回" + fail "/api/health 在 $timeout 秒内没有返回期望版本:实际 $last_version,预期 $expected_version" + fi + fail "/api/health 在 $timeout 秒内没有通过:$health_url" } @@ -400,7 +415,7 @@ if [[ -z "$PUBLIC_URL" ]]; then PUBLIC_URL="$(read_env_value "NEXTAUTH_URL" "$ENV_PATH")" fi [[ -n "$PUBLIC_URL" ]] || fail "未配置 APP_PUBLIC_URL / NEXTAUTH_URL,无法验收健康接口。" -wait_health "${PUBLIC_URL%/}/api/health" "$HEALTH_TIMEOUT_SECONDS" +wait_health "${PUBLIC_URL%/}/api/health" "$HEALTH_TIMEOUT_SECONDS" "$EXPECTED_VERSION" if [[ "$SKIP_MIGRATION_STATUS" -eq 0 ]]; then info "检查数据库迁移状态"