PixelForge / imageforge /scripts /start-prod.ps1
Gregorfun's picture
Initial commit
32c5da4
param(
[string]$BackendHost = "127.0.0.1",
[int]$BackendPort = 8008,
[int]$FrontendPort = 5173,
[int]$HealthTimeoutSeconds = 90,
[string]$PythonExe = "",
[ValidateSet("web", "electron")][string]$FrontendMode = "web",
[switch]$SkipFrontend,
[switch]$RequireA1111
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
Set-Location $projectRoot
function Resolve-PythonExe {
param([string]$Override)
if ($Override -and (Test-Path $Override)) {
return (Resolve-Path $Override).Path
}
$candidates = @(
(Join-Path $projectRoot ".venv\Scripts\python.exe"),
(Join-Path (Split-Path -Parent $projectRoot) ".venv\Scripts\python.exe")
)
foreach ($candidate in $candidates) {
if (Test-Path $candidate) {
return (Resolve-Path $candidate).Path
}
}
throw "Python executable not found. Use -PythonExe <path-to-python.exe>."
}
function Stop-PortListeners {
param([int[]]$Ports)
foreach ($port in $Ports) {
$listeners = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
foreach ($listener in $listeners) {
try {
Stop-Process -Id $listener.OwningProcess -Force -ErrorAction Stop
Write-Host "Stopped PID $($listener.OwningProcess) on port $port"
}
catch {
Write-Host "Could not stop PID $($listener.OwningProcess) on port $port"
}
}
}
}
function Wait-Http {
param(
[Parameter(Mandatory = $true)][string]$Url,
[Parameter(Mandatory = $true)][string]$Name,
[Parameter(Mandatory = $true)][int]$TimeoutSeconds
)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
do {
try {
$response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 5
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 500) {
Write-Host "OK $Name -> $Url"
return
}
}
catch {
Start-Sleep -Milliseconds 800
}
} while ((Get-Date) -lt $deadline)
throw "$Name not reachable within ${TimeoutSeconds}s: $Url"
}
$python = Resolve-PythonExe -Override $PythonExe
$logsDir = Join-Path $projectRoot "logs"
New-Item -ItemType Directory -Force -Path $logsDir | Out-Null
$backendLog = Join-Path $logsDir "backend.log"
$backendErrLog = Join-Path $logsDir "backend.err.log"
$frontendLog = Join-Path $logsDir "frontend.log"
$frontendErrLog = Join-Path $logsDir "frontend.err.log"
Stop-PortListeners -Ports @($BackendPort, $FrontendPort)
$backendCmd = @(
"Set-Location '$projectRoot'",
"`$env:IMAGEFORGE_HOST='$BackendHost'",
"`$env:IMAGEFORGE_PORT='$BackendPort'",
"`$env:IMAGEFORGE_CORS_ORIGINS='http://localhost:$FrontendPort,http://127.0.0.1:$FrontendPort'",
"& '$python' -m backend.app.main"
) -join "; "
$backendProc = Start-Process -FilePath "powershell.exe" -ArgumentList @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-Command", $backendCmd
) -RedirectStandardOutput $backendLog -RedirectStandardError $backendErrLog -PassThru
Write-Host "Backend started (PID $($backendProc.Id))."
$frontendProc = $null
if (-not $SkipFrontend.IsPresent) {
$frontendScript = if ($FrontendMode -eq "electron") { "dev" } else { "dev:web" }
$frontendCheckUrl = if ($FrontendMode -eq "electron") { "http://localhost:$FrontendPort" } else { "http://127.0.0.1:$FrontendPort" }
$frontendCmd = @(
"Set-Location '$projectRoot'",
"npm --prefix frontend run $frontendScript"
) -join "; "
$frontendProc = Start-Process -FilePath "powershell.exe" -ArgumentList @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-Command", $frontendCmd
) -RedirectStandardOutput $frontendLog -RedirectStandardError $frontendErrLog -PassThru
Write-Host "Frontend started (PID $($frontendProc.Id))."
Wait-Http -Url $frontendCheckUrl -Name "Frontend" -TimeoutSeconds $HealthTimeoutSeconds
}
$healthArgs = @(
"-BackendUrl", "http://$BackendHost`:$BackendPort",
"-TimeoutSeconds", "$HealthTimeoutSeconds"
)
if ($RequireA1111.IsPresent) {
$healthArgs += "-RequireA1111"
}
& (Join-Path $PSScriptRoot "healthcheck-stack.ps1") @healthArgs
Write-Host ""
Write-Host "Ready:"
Write-Host "- Backend: http://$BackendHost`:$BackendPort"
if (-not $SkipFrontend.IsPresent) {
if ($FrontendMode -eq "electron") {
Write-Host "- Frontend mode: electron (with embedded Vite on $FrontendPort)"
}
else {
Write-Host "- Frontend (Web): http://localhost:$FrontendPort"
}
}
Write-Host "- Backend log: $backendLog"
Write-Host "- Backend error log: $backendErrLog"
if (-not $SkipFrontend.IsPresent) {
Write-Host "- Frontend log: $frontendLog"
Write-Host "- Frontend error log: $frontendErrLog"
}