공개 런타임 롤백 경계 강화
This commit is contained in:
parent
ff3c79dfc2
commit
aaebe4450e
7 changed files with 1271 additions and 30 deletions
|
|
@ -16,6 +16,8 @@
|
|||
[int]$ApiPort = 8001,
|
||||
[int]$WebPort = 5174,
|
||||
[int]$EnginePort = 9099,
|
||||
[int]$WhisperPort = 9882,
|
||||
[int]$MeloTtsPort = 9883,
|
||||
[string]$Python = "$env:LOCALAPPDATA\Programs\Python\Python311\python.exe",
|
||||
[string]$Cloudflared = "$env:LOCALAPPDATA\Microsoft\WinGet\Links\cloudflared.exe",
|
||||
[string]$CloudflaredConfig = "$env:USERPROFILE\.cloudflared\vignette-config.yml",
|
||||
|
|
@ -36,6 +38,7 @@ $ErrorActionPreference = "Stop"
|
|||
$resolvedSourceRoot = (Resolve-Path -LiteralPath $StableSourceRoot).Path
|
||||
$expectedWatchdogPath = Join-Path $resolvedSourceRoot "scripts\watch-public-runtime.ps1"
|
||||
$startScript = Join-Path $resolvedSourceRoot "scripts\start-public-runtime.ps1"
|
||||
$voiceSidecarProbe = Join-Path $resolvedSourceRoot "scripts\probe-public-voice-sidecars.py"
|
||||
|
||||
function Invoke-GitText {
|
||||
param([string[]]$Arguments)
|
||||
|
|
@ -54,6 +57,9 @@ function Assert-StableSourceProvenance {
|
|||
if (-not (Test-Path -LiteralPath $startScript -PathType Leaf)) {
|
||||
throw "Pinned start script not found at $startScript"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $voiceSidecarProbe -PathType Leaf)) {
|
||||
throw "Pinned voice sidecar probe not found at $voiceSidecarProbe"
|
||||
}
|
||||
|
||||
$runningWatchdogPath = (Resolve-Path -LiteralPath $PSCommandPath).Path
|
||||
if (-not [string]::Equals(
|
||||
|
|
@ -99,7 +105,8 @@ function Assert-StableSourceProvenance {
|
|||
|
||||
foreach ($relativePath in @(
|
||||
"scripts/watch-public-runtime.ps1",
|
||||
"scripts/start-public-runtime.ps1"
|
||||
"scripts/start-public-runtime.ps1",
|
||||
"scripts/probe-public-voice-sidecars.py"
|
||||
)) {
|
||||
Invoke-GitText -Arguments @("ls-files", "--error-unmatch", "--", $relativePath) | Out-Null
|
||||
}
|
||||
|
|
@ -203,6 +210,47 @@ function Get-EngineHeaders {
|
|||
return $null
|
||||
}
|
||||
|
||||
function Test-VoiceApiReady {
|
||||
param([object]$Health)
|
||||
|
||||
return (
|
||||
$null -ne $Health -and
|
||||
$Health.status -eq "ok" -and
|
||||
$Health.available -eq $true -and
|
||||
$Health.stt_available -eq $true -and
|
||||
$Health.tts_available -eq $true -and
|
||||
$Health.stt_provider -eq "local_whisper" -and
|
||||
$Health.stt_model -eq "small" -and
|
||||
$Health.tts_provider -eq "melotts" -and
|
||||
$Health.tts_model -eq "melotts-korean" -and
|
||||
$Health.limits.uvicorn_ws_max_queue -eq 4
|
||||
)
|
||||
}
|
||||
|
||||
function Test-VoiceSidecarStack {
|
||||
$probeArgs = @(
|
||||
"-X", "utf8", "-B", $voiceSidecarProbe,
|
||||
"--component", "all",
|
||||
"--stt-url", "ws://127.0.0.1:$WhisperPort/v1/listen",
|
||||
"--stt-provider", "local_whisper",
|
||||
"--stt-model", "small",
|
||||
"--stt-language", "ko",
|
||||
"--stt-device", "cpu",
|
||||
"--tts-url", "http://127.0.0.1:$MeloTtsPort",
|
||||
"--tts-provider", "melotts",
|
||||
"--tts-model", "melotts-korean",
|
||||
"--tts-language", "KR",
|
||||
"--timeout-seconds", "5"
|
||||
)
|
||||
$output = @(& $Python @probeArgs 2>$null)
|
||||
$probeExit = $LASTEXITCODE
|
||||
return [pscustomobject]@{
|
||||
Name = "voice-sidecars"
|
||||
Ok = $probeExit -eq 0
|
||||
Detail = if ($probeExit -eq 0) { (@($output) -join "") } else { "exact readiness probe failed" }
|
||||
}
|
||||
}
|
||||
|
||||
function Test-CloudflaredProcess {
|
||||
if ($SkipCloudflaredRestart) {
|
||||
return [pscustomobject]@{
|
||||
|
|
@ -245,10 +293,16 @@ $checks = @(
|
|||
-Uri "http://127.0.0.1:$ApiPort/health" `
|
||||
-IsHealthy { param($health) $health.environment -eq "prod" -and $health.db -and $health.engine } `
|
||||
-TimeoutSec 60),
|
||||
(Test-JsonHealth `
|
||||
-Name "voice-api" `
|
||||
-Uri "http://127.0.0.1:$ApiPort/voice/health" `
|
||||
-IsHealthy { param($health) Test-VoiceApiReady -Health $health } `
|
||||
-TimeoutSec 30),
|
||||
(Test-JsonHealth `
|
||||
-Name "web-preview" `
|
||||
-Uri "http://127.0.0.1:$WebPort/" `
|
||||
-IsHealthy { param($body) $true }),
|
||||
(Test-VoiceSidecarStack),
|
||||
(Test-CloudflaredProcess)
|
||||
)
|
||||
|
||||
|
|
@ -294,6 +348,8 @@ $startArgs = @{
|
|||
ApiPort = $ApiPort
|
||||
WebPort = $WebPort
|
||||
EnginePort = $EnginePort
|
||||
WhisperPort = $WhisperPort
|
||||
MeloTtsPort = $MeloTtsPort
|
||||
Python = $Python
|
||||
Cloudflared = $Cloudflared
|
||||
CloudflaredConfig = $CloudflaredConfig
|
||||
|
|
@ -324,6 +380,15 @@ if (!$apiAfter.Ok) {
|
|||
throw "Public API still unhealthy after restart: $($apiAfter.Detail)"
|
||||
}
|
||||
|
||||
$voiceApiAfter = Test-JsonHealth `
|
||||
-Name "voice-api" `
|
||||
-Uri "http://127.0.0.1:$ApiPort/voice/health" `
|
||||
-IsHealthy { param($health) Test-VoiceApiReady -Health $health } `
|
||||
-TimeoutSec 30
|
||||
if (!$voiceApiAfter.Ok) {
|
||||
throw "Public voice API still does not expose the exact local provider/model contract after restart: $($voiceApiAfter.Detail)"
|
||||
}
|
||||
|
||||
$webAfter = Test-JsonHealth `
|
||||
-Name "web-preview" `
|
||||
-Uri "http://127.0.0.1:$WebPort/" `
|
||||
|
|
@ -343,6 +408,11 @@ if (!$engineAfter.Ok) {
|
|||
throw "Engine gateway still unhealthy after isolated restart: $($engineAfter.Detail)"
|
||||
}
|
||||
|
||||
$voiceSidecarsAfter = Test-VoiceSidecarStack
|
||||
if (!$voiceSidecarsAfter.Ok) {
|
||||
throw "Exact local voice sidecars still unhealthy after restart"
|
||||
}
|
||||
|
||||
if (!$SkipPublicHealth) {
|
||||
$publicAfter = Test-JsonHealth `
|
||||
-Name "public-api" `
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue