fix: harden real backend workflows and channel connections
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
param(
|
||||
[switch]$SkipInfra,
|
||||
[switch]$SkipMigrate,
|
||||
[switch]$SkipApi,
|
||||
[switch]$SkipWeb,
|
||||
[switch]$WithGateway,
|
||||
[switch]$OnlyMinio
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Resolve-Path (Join-Path $PSScriptRoot '..')
|
||||
$logDir = Join-Path $root 'logs'
|
||||
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
|
||||
|
||||
function Test-CommandAvailable {
|
||||
param([string]$Name)
|
||||
return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
function Test-PortOpen {
|
||||
param([int]$Port)
|
||||
return [bool](Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
function Test-TcpPort {
|
||||
param(
|
||||
[string]$HostName,
|
||||
[int]$Port
|
||||
)
|
||||
|
||||
try {
|
||||
$client = [System.Net.Sockets.TcpClient]::new()
|
||||
$connect = $client.BeginConnect($HostName, $Port, $null, $null)
|
||||
if (-not $connect.AsyncWaitHandle.WaitOne(1000)) {
|
||||
$client.Close()
|
||||
return $false
|
||||
}
|
||||
$client.EndConnect($connect)
|
||||
$client.Close()
|
||||
return $true
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Start-LoggedProcess {
|
||||
param(
|
||||
[string]$Name,
|
||||
[string]$FilePath,
|
||||
[string[]]$ArgumentList,
|
||||
[string]$WorkingDirectory,
|
||||
[string]$OutLog,
|
||||
[string]$ErrLog
|
||||
)
|
||||
|
||||
Write-Host "Starting $Name..."
|
||||
Start-Process `
|
||||
-FilePath $FilePath `
|
||||
-ArgumentList $ArgumentList `
|
||||
-WorkingDirectory $WorkingDirectory `
|
||||
-RedirectStandardOutput $OutLog `
|
||||
-RedirectStandardError $ErrLog `
|
||||
-WindowStyle Hidden | Out-Null
|
||||
}
|
||||
|
||||
function Wait-ForTcpPort {
|
||||
param(
|
||||
[string]$Name,
|
||||
[string]$HostName,
|
||||
[int]$Port,
|
||||
[int]$TimeoutSeconds = 20
|
||||
)
|
||||
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
if (Test-TcpPort -HostName $HostName -Port $Port) {
|
||||
Write-Host "$Name is listening on ${HostName}:$Port."
|
||||
return $true
|
||||
}
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
|
||||
Write-Host "$Name is not listening on ${HostName}:$Port after ${TimeoutSeconds}s."
|
||||
return $false
|
||||
}
|
||||
|
||||
function Find-LocalPostgresBin {
|
||||
$candidates = @(
|
||||
'C:\cmpp-platform-local\pgsql\bin',
|
||||
'C:\cmpp-platform-local\PostgreSQL16\bin',
|
||||
'C:\Program Files\PostgreSQL\16\bin'
|
||||
)
|
||||
|
||||
foreach ($candidate in $candidates) {
|
||||
if ((Test-Path (Join-Path $candidate 'pg_ctl.exe')) -and (Test-Path (Join-Path $candidate 'pg_isready.exe'))) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
|
||||
$pgCtl = Get-Command 'pg_ctl.exe' -ErrorAction SilentlyContinue
|
||||
if ($pgCtl) {
|
||||
return Split-Path $pgCtl.Source -Parent
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Start-LocalPostgres {
|
||||
if (Test-TcpPort -HostName '127.0.0.1' -Port 5432) {
|
||||
Write-Host 'PostgreSQL is already reachable on 127.0.0.1:5432.'
|
||||
return $true
|
||||
}
|
||||
|
||||
$pgBin = Find-LocalPostgresBin
|
||||
$pgData = 'C:\cmpp-platform-local\postgres-data'
|
||||
if (-not $pgBin -or -not (Test-Path (Join-Path $pgData 'PG_VERSION'))) {
|
||||
Write-Host 'PostgreSQL is not reachable and no local PostgreSQL data directory was found.'
|
||||
Write-Host 'Expected Docker Compose or local data at C:\cmpp-platform-local\postgres-data.'
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Host "Starting local PostgreSQL from $pgData..."
|
||||
& (Join-Path $pgBin 'pg_ctl.exe') -D $pgData -l (Join-Path $logDir 'postgres.log') start | Out-Host
|
||||
Start-Sleep -Seconds 2
|
||||
if (Test-Path (Join-Path $pgBin 'pg_isready.exe')) {
|
||||
& (Join-Path $pgBin 'pg_isready.exe') -h 127.0.0.1 -p 5432 -U cmpp -d cmpp_platform | Out-Host
|
||||
}
|
||||
return (Wait-ForTcpPort -Name 'PostgreSQL' -HostName '127.0.0.1' -Port 5432 -TimeoutSeconds 30)
|
||||
}
|
||||
|
||||
function Start-LocalRedis {
|
||||
if (Test-TcpPort -HostName '127.0.0.1' -Port 6379) {
|
||||
Write-Host 'Redis is already reachable on 127.0.0.1:6379.'
|
||||
return $true
|
||||
}
|
||||
|
||||
$redisServer = Get-Command 'redis-server' -ErrorAction SilentlyContinue
|
||||
if (-not $redisServer) {
|
||||
Write-Host 'Redis is not reachable and redis-server was not found in PATH.'
|
||||
return $false
|
||||
}
|
||||
|
||||
$redisDir = Join-Path $root '.local-data\redis'
|
||||
New-Item -ItemType Directory -Force -Path $redisDir | Out-Null
|
||||
|
||||
Start-LoggedProcess `
|
||||
-Name 'Redis' `
|
||||
-FilePath $redisServer.Source `
|
||||
-ArgumentList @('--port', '6379', '--dir', $redisDir, '--dbfilename', 'dump.rdb') `
|
||||
-WorkingDirectory $root `
|
||||
-OutLog (Join-Path $logDir 'redis.out.log') `
|
||||
-ErrLog (Join-Path $logDir 'redis.err.log')
|
||||
|
||||
return (Wait-ForTcpPort -Name 'Redis' -HostName '127.0.0.1' -Port 6379 -TimeoutSeconds 15)
|
||||
}
|
||||
|
||||
function Find-LocalMinio {
|
||||
$candidates = @(
|
||||
'C:\cmpp-platform-local\minio.exe',
|
||||
'C:\cmpp-platform-local\minio\minio.exe'
|
||||
)
|
||||
|
||||
foreach ($candidate in $candidates) {
|
||||
if (Test-Path $candidate) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
|
||||
$minio = Get-Command 'minio.exe' -ErrorAction SilentlyContinue
|
||||
if ($minio) {
|
||||
return $minio.Source
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Start-LocalMinio {
|
||||
if ((Test-TcpPort -HostName '127.0.0.1' -Port 9000) -and (Test-TcpPort -HostName '127.0.0.1' -Port 9001)) {
|
||||
Write-Host 'MinIO is already reachable on 127.0.0.1:9000/9001.'
|
||||
return $true
|
||||
}
|
||||
|
||||
$minio = Find-LocalMinio
|
||||
if (-not $minio) {
|
||||
Write-Host 'MinIO is not reachable and minio.exe was not found.'
|
||||
Write-Host 'Expected minio.exe at C:\cmpp-platform-local\minio.exe or in PATH.'
|
||||
return $false
|
||||
}
|
||||
|
||||
$minioData = 'C:\cmpp-platform-local\minio-data'
|
||||
New-Item -ItemType Directory -Force -Path $minioData | Out-Null
|
||||
if (-not $env:MINIO_ROOT_USER) {
|
||||
$env:MINIO_ROOT_USER = 'cmpp_minio'
|
||||
}
|
||||
if (-not $env:MINIO_ROOT_PASSWORD) {
|
||||
$env:MINIO_ROOT_PASSWORD = 'cmpp_minio_password'
|
||||
}
|
||||
|
||||
Start-LoggedProcess `
|
||||
-Name 'MinIO' `
|
||||
-FilePath $minio `
|
||||
-ArgumentList @('server', $minioData, '--address', ':9000', '--console-address', ':9001') `
|
||||
-WorkingDirectory (Split-Path $minio -Parent) `
|
||||
-OutLog (Join-Path $logDir 'minio.out.log') `
|
||||
-ErrLog (Join-Path $logDir 'minio.err.log')
|
||||
|
||||
$apiReady = Wait-ForTcpPort -Name 'MinIO API' -HostName '127.0.0.1' -Port 9000 -TimeoutSeconds 20
|
||||
$consoleReady = Wait-ForTcpPort -Name 'MinIO Console' -HostName '127.0.0.1' -Port 9001 -TimeoutSeconds 20
|
||||
return ($apiReady -and $consoleReady)
|
||||
}
|
||||
|
||||
function Test-Minio {
|
||||
if ((Test-TcpPort -HostName '127.0.0.1' -Port 9000) -and (Test-TcpPort -HostName '127.0.0.1' -Port 9001)) {
|
||||
Write-Host 'MinIO ports 9000/9001 are reachable.'
|
||||
return $true
|
||||
}
|
||||
|
||||
Write-Host 'MinIO is not fully reachable on 9000/9001. File upload smoke may be blocked.'
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Host "CMPP local service startup"
|
||||
Write-Host "Workspace: $root"
|
||||
|
||||
$minioReady = $false
|
||||
if ($OnlyMinio) {
|
||||
$minioReady = Start-LocalMinio
|
||||
if (-not $minioReady) {
|
||||
exit 1
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host 'MinIO startup command issued. Useful URLs:'
|
||||
Write-Host ' MinIO API: http://localhost:9000'
|
||||
Write-Host ' MinIO Console: http://localhost:9001'
|
||||
Write-Host ''
|
||||
Write-Host "Logs: $logDir"
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $SkipInfra) {
|
||||
if (Test-CommandAvailable 'docker') {
|
||||
Write-Host "Starting PostgreSQL, Redis and MinIO via Docker Compose..."
|
||||
& docker compose -f (Join-Path $root 'infra/docker-compose.yml') up -d
|
||||
Wait-ForTcpPort -Name 'PostgreSQL' -HostName '127.0.0.1' -Port 5432 -TimeoutSeconds 30 | Out-Null
|
||||
Wait-ForTcpPort -Name 'Redis' -HostName '127.0.0.1' -Port 6379 -TimeoutSeconds 20 | Out-Null
|
||||
$minioReady = Test-Minio
|
||||
} else {
|
||||
Write-Host "Docker CLI is not available. Trying local PostgreSQL and Redis fallback..."
|
||||
Start-LocalPostgres | Out-Null
|
||||
Start-LocalRedis | Out-Null
|
||||
$minioReady = Start-LocalMinio
|
||||
}
|
||||
} else {
|
||||
$minioReady = Test-Minio
|
||||
}
|
||||
|
||||
if (-not $minioReady) {
|
||||
$localObjectRoot = Join-Path $root '.local-data\object-storage'
|
||||
New-Item -ItemType Directory -Force -Path $localObjectRoot | Out-Null
|
||||
$env:OBJECT_STORAGE_DRIVER = 'local'
|
||||
$env:OBJECT_STORAGE_LOCAL_ROOT = $localObjectRoot
|
||||
Write-Host "Object storage fallback enabled: $localObjectRoot"
|
||||
}
|
||||
|
||||
if (-not $SkipInfra -and -not $SkipMigrate -and (Test-TcpPort -HostName '127.0.0.1' -Port 5432)) {
|
||||
Write-Host 'Applying Prisma migrations...'
|
||||
& npm.cmd --prefix api run prisma:migrate:deploy
|
||||
}
|
||||
|
||||
if (-not $SkipApi) {
|
||||
if (Test-PortOpen 3000) {
|
||||
Write-Host "API port 3000 is already listening; leaving the existing API process untouched."
|
||||
} else {
|
||||
Start-LoggedProcess `
|
||||
-Name 'NestJS API' `
|
||||
-FilePath 'npm.cmd' `
|
||||
-ArgumentList @('--prefix', 'api', 'run', 'start:dev') `
|
||||
-WorkingDirectory $root `
|
||||
-OutLog (Join-Path $logDir 'api-dev.out.log') `
|
||||
-ErrLog (Join-Path $logDir 'api-dev.err.log')
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipWeb) {
|
||||
if ((Test-PortOpen 5173) -or (Test-PortOpen 4173) -or (Test-PortOpen 4174)) {
|
||||
Write-Host "A frontend port is already listening on 5173/4173/4174; leaving the existing web process untouched."
|
||||
} else {
|
||||
Start-LoggedProcess `
|
||||
-Name 'frontend preview' `
|
||||
-FilePath 'npm.cmd' `
|
||||
-ArgumentList @('run', 'dev') `
|
||||
-WorkingDirectory $root `
|
||||
-OutLog (Join-Path $logDir 'frontend-dev.out.log') `
|
||||
-ErrLog (Join-Path $logDir 'frontend-dev.err.log')
|
||||
}
|
||||
}
|
||||
|
||||
if ($WithGateway) {
|
||||
if (-not (Test-CommandAvailable 'go')) {
|
||||
Write-Host "Go CLI is not available. Skipping gateway startup."
|
||||
} elseif (Test-PortOpen 8090) {
|
||||
Write-Host "Gateway health port 8090 is already listening; leaving the existing gateway process untouched."
|
||||
} else {
|
||||
Start-LoggedProcess `
|
||||
-Name 'Go gateway' `
|
||||
-FilePath 'go' `
|
||||
-ArgumentList @('run', './cmd/gateway') `
|
||||
-WorkingDirectory (Join-Path $root 'gateway') `
|
||||
-OutLog (Join-Path $logDir 'gateway.out.log') `
|
||||
-ErrLog (Join-Path $logDir 'gateway.err.log')
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host 'Startup command issued. Useful URLs:'
|
||||
Write-Host ' API: http://localhost:3000/api'
|
||||
Write-Host ' Frontend: http://localhost:5173 or http://localhost:4173'
|
||||
if ($minioReady) {
|
||||
Write-Host ' MinIO: http://localhost:9001'
|
||||
} else {
|
||||
Write-Host ' MinIO: not running; using local object storage fallback when API is started by this script'
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host "Logs: $logDir"
|
||||
Reference in New Issue
Block a user