# CE-001: 数据库不可用韧性验证 # 验证:当数据库连接中断时,健康检查正确返回 DOWN,API 返回 503 param( [string]$BaseURL = "http://localhost:8080", [string]$DBPath = ".\data\user_management.db", [int]$TimeoutSeconds = 30 ) $ErrorActionPreference = "Stop" $passed = 0 $failed = 0 function Write-Pass { param($msg) Write-Host " ✅ $msg" -ForegroundColor Green; $script:passed++ } function Write-Fail { param($msg) Write-Host " ❌ $msg" -ForegroundColor Red; $script:failed++ } function Write-Step { param($msg) Write-Host "`n[STEP] $msg" -ForegroundColor Cyan } Write-Host "=== CE-001: 数据库不可用韧性验证 ===" -ForegroundColor Magenta Write-Host "目标服务: $BaseURL" Write-Host "数据库路径: $DBPath" Write-Host "" # 前置检查:服务必须正常运行 Write-Step "前置检查:验证服务初始状态" try { $health = Invoke-RestMethod -Uri "$BaseURL/health/ready" -TimeoutSec 5 if ($health.status -eq "UP") { Write-Pass "服务初始状态 UP" } else { Write-Fail "服务初始状态不健康 ($($health.status)),请先启动服务" exit 1 } } catch { Write-Fail "无法连接到服务: $($_.Exception.Message)" exit 1 } # 记录实验前指标 Write-Step "记录实验前基线指标" try { $beforeMetrics = Invoke-RestMethod -Uri "$BaseURL/metrics" -TimeoutSec 5 Write-Pass "基线指标已记录" } catch { Write-Host " ℹ️ /metrics 端点未就绪(可能是 P0 修复前状态),跳过指标记录" } # 注意:此脚本为"观察模式",不实际关闭数据库 # 在生产混沌实验中,应使用专用的故障注入工具 Write-Step "故障注入模拟(观察模式)" Write-Host " ℹ️ 本实验为观察模式,不实际关闭数据库" -ForegroundColor Yellow Write-Host " ℹ️ 生产环境请使用: chaostoolkit / Gremlin / 手动关闭 DB 进程" # 模拟:快速连续请求,观察健康检查行为 Write-Step "并发健康检查验证" $jobs = 1..5 | ForEach-Object { Start-Job -ScriptBlock { param($url) try { $resp = Invoke-RestMethod -Uri "$url/health/ready" -TimeoutSec 3 return @{ status = $resp.status; ok = $true } } catch { return @{ status = "ERROR"; ok = $false; error = $_.Exception.Message } } } -ArgumentList $BaseURL } $results = $jobs | Wait-Job | Receive-Job $allUp = ($results | Where-Object { $_.status -ne "UP" }).Count -eq 0 if ($allUp) { Write-Pass "5次并发健康检查全部返回 UP" } else { Write-Fail "部分健康检查失败: $($results | ConvertTo-Json -Compress)" } # 验证健康检查格式是否符合规范 Write-Step "验证健康检查响应格式" try { $health = Invoke-RestMethod -Uri "$BaseURL/health/ready" -TimeoutSec 5 if ($health.status) { Write-Pass "包含 status 字段: $($health.status)" } else { Write-Fail "缺少 status 字段" } if ($health.checks) { Write-Pass "包含 checks 字段" } else { Write-Fail "缺少 checks 字段" } if ($health.timestamp) { Write-Pass "包含 timestamp 字段: $($health.timestamp)" } else { Write-Fail "缺少 timestamp 字段(需要升级 health.go)" } if ($health.checks.database) { Write-Pass "database 检查存在: $($health.checks.database.status)" } else { Write-Fail "缺少 database 检查" } } catch { Write-Fail "健康检查请求失败: $($_.Exception.Message)" } # 验证 Liveness 端点(应始终返回成功) Write-Step "验证 Liveness 端点(应始终成功)" try { $resp = Invoke-WebRequest -Uri "$BaseURL/health/live" -TimeoutSec 5 if ($resp.StatusCode -eq 200 -or $resp.StatusCode -eq 204) { Write-Pass "Liveness 检查返回 $($resp.StatusCode)" } else { Write-Fail "Liveness 检查返回非成功状态: $($resp.StatusCode)" } } catch { Write-Fail "Liveness 检查失败: $($_.Exception.Message)" } # 汇总 Write-Host "`n=== 实验结果 ===" -ForegroundColor Magenta Write-Host "通过: $passed" Write-Host "失败: $failed" if ($failed -eq 0) { Write-Host "`n✅ CE-001 观察阶段通过" -ForegroundColor Green Write-Host "⚠️ 完整实验需要手动关闭数据库并验证 503 响应" -ForegroundColor Yellow exit 0 } else { Write-Host "`n❌ CE-001 存在 $failed 个验证失败" -ForegroundColor Red exit 1 }