pm2_watchdog.ps1

# pm2_watchdog.ps1
$ErrorActionPreference = 'Stop'

# ── Konfiguration ──────────────────────────────────────────────
$workDir       = 'C:\FastStats\Scripts\node_webhook'
$logFile       = Join-Path $workDir 'logs\watchdog.log'
$pm2Home       = Join-Path $workDir '.pm2'
$nodeExe       = 'C:\Program Files\nodejs\node.exe'
$pm2Bin        = 'C:\Program Files\nodejs\node_modules\pm2\bin\pm2'   # ggf. anpassen
$ecosystemFile = Join-Path $workDir 'ecosystem.config.js'
$expectedApps  = @('webhook-receiver','webhook-worker')

# ── Vorbereitung ───────────────────────────────────────────────
$env:PM2_HOME = $pm2Home

Import-Module WriteLog
$logDir = Split-Path $logFile -Parent
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }
Set-Logfile -Path $logFile

# ── PM2-Helfer ─────────────────────────────────────────────────
function Invoke-Pm2 {
    param([string[]]$Arguments)
    return (& $nodeExe $pm2Bin @Arguments 2>&1) -join "`n"
}

function Get-Pm2Procs {
    $raw = Invoke-Pm2 @('jlist')
    $i = $raw.IndexOf('[')
    if ($i -lt 0) { return $null }            # Daemon nicht erreichbar
    try { return ($raw.Substring($i) | ConvertFrom-Json -AsHashtable) }
    catch { return $null }
}

function Start-Pm2Apps {
    # startet alle Apps deterministisch aus der ecosystem-Datei
    Write-Log -Message "Starte Apps aus $ecosystemFile." -Severity WARNING
    Invoke-Pm2 @('start', $ecosystemFile) | Out-Null
    Start-Sleep -Seconds 3
}

# ── 1. Daemon-Check (z.B. nach Reboot) ─────────────────────────
$procs = Get-Pm2Procs
$didStart = $false

if ($null -eq $procs) {
    Write-Log -Message 'PM2-Daemon nicht erreichbar — starte Apps neu.' -Severity WARNING
    Start-Pm2Apps
    $didStart = $true
    $procs = Get-Pm2Procs
}

# ── 2. App-Status prüfen ───────────────────────────────────────
$problems = @()

foreach ($name in $expectedApps) {
    $p = $procs | Where-Object { $_.name -eq $name }

    if (-not $p) {
        $problems += "$name fehlt"
        if (-not $didStart) {
            Write-Log -Message "$name fehlt in PM2 — starte aus ecosystem." -Severity WARNING
            Start-Pm2Apps
            $didStart = $true
            $procs = Get-Pm2Procs
        }
    }
    elseif ($p.pm2_env.status -ne 'online') {
        $problems += "$name ist $($p.pm2_env.status)"
        Write-Log -Message "$name ist '$($p.pm2_env.status)' — restart." -Severity WARNING
        Invoke-Pm2 @('restart', $name) | Out-Null
    }
}

# ── 3. Ergebnis loggen ─────────────────────────────────────────
if ($problems.Count -eq 0 -and -not $didStart) {
    Write-Log -Message "OK — alle Apps online: $($expectedApps -join ', ')." -Severity VERBOSE
} else {
    Start-Sleep -Seconds 2
    $final = Get-Pm2Procs
    $states = foreach ($name in $expectedApps) {
        $p = $final | Where-Object { $_.name -eq $name }
        if ($p) { "$name=$($p.pm2_env.status)" } else { "$name=fehlt" }
    }
    Write-Log -Message "Nach Reparatur: $($states -join ', ')." -Severity INFO
}