162 lines
6.9 KiB
PowerShell
162 lines
6.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
ObsiGate — cycle de vie du serveur E2E local, avec progression visible.
|
|
|
|
.DESCRIPTION
|
|
Remplace le one-liner opaque de démarrage : chaque étape affiche sa
|
|
progression (port, PID, attente du health check seconde par seconde,
|
|
version servie). Memes conditions que le job CI `e2e` et que
|
|
`scripts/run-e2e-local.ps1` : uvicorn natif, auth désactivée, fixtures
|
|
TestVault/TestDir, port 2029.
|
|
|
|
Le PID est persisté dans `data/e2e-server.pid` pour un arrêt propre
|
|
(`stop`) — plus de serveurs orphelins qui squattent le port.
|
|
|
|
.EXAMPLE
|
|
./scripts/e2e-server.ps1 start # démarre + attend READY (défaut)
|
|
./scripts/e2e-server.ps1 status # port, PID, version servie
|
|
./scripts/e2e-server.ps1 logs # queues des logs serveur
|
|
./scripts/e2e-server.ps1 stop # arrête le serveur + libère le port
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Position = 0)]
|
|
[ValidateSet("start", "stop", "status", "logs")]
|
|
[string]$Command = "start",
|
|
|
|
[string]$Port = $(if ($env:E2E_PORT) { $env:E2E_PORT } else { "2029" })
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$Root = Split-Path -Parent $PSScriptRoot
|
|
Set-Location -LiteralPath $Root
|
|
|
|
$BaseUrl = "http://127.0.0.1:$Port"
|
|
$Python = ".\.venv\Scripts\python.exe"
|
|
$PidFile = "data/e2e-server.pid"
|
|
$OutLog = "data/e2e-server.log"
|
|
$ErrLog = "data/e2e-server.err.log"
|
|
|
|
function Get-PortOwner {
|
|
$conn = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue |
|
|
Select-Object -First 1
|
|
if (-not $conn) { return $null }
|
|
$proc = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
|
|
return @{ Pid = $conn.OwningProcess; Name = $(if ($proc) { $proc.ProcessName } else { "?" }) }
|
|
}
|
|
|
|
function Stop-Server {
|
|
param([string]$Why = "")
|
|
$killed = @()
|
|
if (Test-Path -LiteralPath $PidFile) {
|
|
$srvPid = (Get-Content -LiteralPath $PidFile -TotalCount 1).Trim()
|
|
if ($srvPid -match '^\d+$') {
|
|
# BUG-080 : le PID enregistré peut avoir ré-exécuté uvicorn dans un
|
|
# processus enfant (constaté : parent .venv + enfant uv-python sur
|
|
# le port) — tuer l'arbre complet, pas seulement la racine.
|
|
Get-CimInstance Win32_Process -Filter "ParentProcessId=$srvPid" -ErrorAction SilentlyContinue |
|
|
ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue; $killed += $_.ProcessId }
|
|
Stop-Process -Id $srvPid -Force -ErrorAction SilentlyContinue
|
|
$killed += $srvPid
|
|
}
|
|
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
$owner = Get-PortOwner
|
|
if ($owner) {
|
|
Stop-Process -Id $owner.Pid -Force -ErrorAction SilentlyContinue
|
|
$killed += $owner.Pid
|
|
}
|
|
if ($killed.Count) { Write-Host "[OK] Serveur arrêté (PID $($killed -join ', ')). $Why" }
|
|
else { Write-Host "[OK] Aucun serveur en cours (port $Port libre)." }
|
|
}
|
|
|
|
switch ($Command) {
|
|
"stop" {
|
|
Write-Host "[1/1] Arrêt du serveur E2E (port $Port)..."
|
|
Stop-Server
|
|
}
|
|
|
|
"status" {
|
|
$owner = Get-PortOwner
|
|
if (-not $owner) { Write-Host "[INFO] Port $Port libre, aucun serveur."; break }
|
|
Write-Host "[INFO] Port $Port occupé par PID $($owner.Pid) ($($owner.Name))."
|
|
try {
|
|
$health = Invoke-WebRequest -Uri "$BaseUrl/api/health" -TimeoutSec 5 -UseBasicParsing |
|
|
Select-Object -ExpandProperty Content | ConvertFrom-Json
|
|
Write-Host "[OK] Health 200 — version $($health.version), $($health.total_files) fichiers indexés."
|
|
} catch {
|
|
Write-Host "[WARN] Processus présent mais health injoignable : $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
"logs" {
|
|
Write-Host "===== $OutLog (stdout) ====="
|
|
Get-Content -LiteralPath $OutLog -Tail 15 -ErrorAction SilentlyContinue
|
|
Write-Host "===== $ErrLog (stderr) ====="
|
|
Get-Content -LiteralPath $ErrLog -Tail 25 -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
"start" {
|
|
Write-Host "[1/4] Port $Port..."
|
|
$owner = Get-PortOwner
|
|
if ($owner) {
|
|
Write-Host "[ERR] Port $Port déjà occupé par PID $($owner.Pid) ($($owner.Name))."
|
|
Write-Host " Lancez d'abord : ./scripts/e2e-server.ps1 stop"
|
|
exit 1
|
|
}
|
|
Write-Host " libre."
|
|
|
|
Write-Host "[2/4] Interpréteur $Python..."
|
|
if (-not (Test-Path -LiteralPath $Python)) {
|
|
Write-Host "[ERR] $Python introuvable. Créez le venv (voir AGENTS.md)."
|
|
exit 1
|
|
}
|
|
Write-Host " présent."
|
|
New-Item -ItemType Directory -Force -Path "data" | Out-Null
|
|
|
|
Write-Host "[3/4] Démarrage uvicorn (auth désactivée, TestVault/TestDir)..."
|
|
$env:OBSIGATE_AUTH_ENABLED = "false"
|
|
$env:VAULT_1_NAME = "TestVault"
|
|
$env:VAULT_1_PATH = (Resolve-Path -LiteralPath "test_vault").Path
|
|
$env:DIR_1_NAME = "TestDir"
|
|
$env:DIR_1_PATH = (Resolve-Path -LiteralPath "test_dir").Path
|
|
$server = Start-Process -FilePath $Python `
|
|
-ArgumentList "-m", "uvicorn", "backend.main:app", "--host", "127.0.0.1", "--port", $Port `
|
|
-RedirectStandardOutput $OutLog -RedirectStandardError $ErrLog `
|
|
-PassThru -WindowStyle Hidden
|
|
$server.Id | Set-Content -LiteralPath $PidFile
|
|
Write-Host " PID $($server.Id) (logs : $OutLog / $ErrLog)."
|
|
|
|
Write-Host "[4/4] Attente du health check (30 s max)..."
|
|
$ready = $false
|
|
for ($i = 1; $i -le 30; $i++) {
|
|
try {
|
|
Invoke-WebRequest -Uri "$BaseUrl/api/health" -TimeoutSec 2 -UseBasicParsing | Out-Null
|
|
$ready = $true
|
|
break
|
|
} catch {
|
|
if ($server.HasExited) {
|
|
Write-Host "[ERR] Le serveur a quitté (code $($server.ExitCode)). Fin du log :"
|
|
Get-Content -LiteralPath $ErrLog -Tail 15 -ErrorAction SilentlyContinue
|
|
exit 1
|
|
}
|
|
if ($i % 5 -eq 0) { Write-Host " ... $i/30 s (indexation en cours, voir $ErrLog)" }
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
}
|
|
if (-not $ready) {
|
|
Write-Host "[ERR] Injoignable après 30 s. Fin du log :"
|
|
Get-Content -LiteralPath $ErrLog -Tail 15 -ErrorAction SilentlyContinue
|
|
exit 1
|
|
}
|
|
$health = Invoke-WebRequest -Uri "$BaseUrl/api/health" -TimeoutSec 5 -UseBasicParsing |
|
|
Select-Object -ExpandProperty Content | ConvertFrom-Json
|
|
# BUG-080 : le PID `Start-Process` peut ne pas être celui qui écoute
|
|
# (ré-exécution enfant constatée) — persister le vrai propriétaire du
|
|
# port pour un `stop` fiable, sans serveurs orphelins.
|
|
$owner = Get-PortOwner
|
|
if ($owner) { $owner.Pid | Set-Content -LiteralPath $PidFile }
|
|
Write-Host "[OK] READY — ObsiGate v$($health.version) sur $BaseUrl ($($health.total_files) fichiers)."
|
|
}
|
|
}
|