재부팅 복구와 학습자 패널을 정리

This commit is contained in:
Yun Chan 2026-08-28 18:07:28 +09:00
parent dcb76a2373
commit 99779a6ab2
10 changed files with 442 additions and 25 deletions

View file

@ -311,7 +311,7 @@ function Test-DatabaseListening {
# 재시작 전에 컨테이너를 직접 되살린다.
function Restore-DatabaseContainer {
try {
$output = & docker.exe start $DbContainer 2>&1
$output = & docker.exe start $DbContainer 2>$null
$output | ForEach-Object { Write-WatchdogLog " docker> $_" }
if ($LASTEXITCODE -ne 0) {
Write-WatchdogLog "db restore: docker start exit=$LASTEXITCODE"
@ -329,6 +329,17 @@ function Restore-DatabaseContainer {
return $false
}
function Test-PublicRuntimeHardDown {
param([string[]]$FailedNames)
$allLocalSurfacesDown = (
($FailedNames -contains "api") -and
($FailedNames -contains "web-preview") -and
($FailedNames -contains "voice-sidecars")
)
return ($FailedNames -contains "cloudflared") -or $allLocalSurfacesDown
}
# engine 판정은 /health(프로세스 liveness)가 아니라 /ready(실제 claude -p 생성)로 한다.
# /health는 ok:true만 보므로 "프로세스는 살아 있고 그 프로세스의 claude 세션만 죽은"
# 상태를 통과시킨다(2026-08-07 공개 런타임: engine=false인데 워치독 lastResult=0).
@ -376,6 +387,14 @@ if (!$SkipPublicHealth) {
}
$failed = @($checks | Where-Object { -not $_.Ok })
if ($CheckOnly) {
if ($failed.Count -eq 0) {
Write-Output "healthy: $($checks.Name -join ', ')"
exit 0
}
Write-Output "unhealthy: $((($failed | ForEach-Object { "$($_.Name)=$($_.Detail)" }) -join '; '))"
exit 1
}
if ($failed.Count -eq 0) {
Set-FailCount 0
Write-WatchdogLog "healthy: $($checks.Name -join ', ')"
@ -385,17 +404,20 @@ if ($failed.Count -eq 0) {
$failCount = (Get-FailCount) + 1
Set-FailCount $failCount
Write-WatchdogLog "unhealthy ($failCount/$FailuresBeforeRestart): $((($failed | ForEach-Object { "$($_.Name)=$($_.Detail)" }) -join '; '))"
if ($CheckOnly) {
exit 1
}
# 연속 실패 debounce: claude -p readiness probe 는 콜드 스폰 시 10~20초가 정상이라
# 단발 timeout 을 장애로 오판해 전체 재시작하던 것이 재시작 폭풍의 원인이었다.
# 연속 $FailuresBeforeRestart 회 실패해야 실제 재시작한다.
if ($failCount -lt $FailuresBeforeRestart) {
# 다만 cloudflared가 사라졌거나 API·web·voice sidecar가 함께 죽은 경우는 transient
# readiness가 아니라 공개 서비스 전체 소실이므로 첫 감지에서 즉시 복구한다.
$failedNames = @($failed | ForEach-Object { $_.Name })
$hardDown = Test-PublicRuntimeHardDown -FailedNames $failedNames
if ($failCount -lt $FailuresBeforeRestart -and -not $hardDown) {
Write-WatchdogLog "defer restart: $FailuresBeforeRestart 연속 실패 전까지 대기 (현재 $failCount)"
exit 1
}
if ($hardDown -and $failCount -lt $FailuresBeforeRestart) {
Write-WatchdogLog "immediate restart: public runtime hard-down detected"
}
# DB가 죽어 있으면 start-public-runtime.ps1으로는 절대 복구되지 않는다(DB 기동은 boot 담당).
# 먼저 되살리고, 그래도 안 되면 재시작을 아예 시도하지 않는다 — 고칠 수 없는 대상에
@ -429,7 +451,7 @@ if ($SkipCloudflaredRestart) {
}
try {
& $startScript @startArgs 2>&1 | ForEach-Object {
& $startScript @startArgs | ForEach-Object {
Write-WatchdogLog "$_"
}
} catch {