Files
Edu/scripts/start-all.ps1
SpecialX f1e466a772
Some checks failed
CI / quality-go (push) Failing after 5s
CI / quality-proto (push) Failing after 3s
CI / deploy (push) Has been skipped
CI / quality-ts (push) Failing after 50s
fix(infra): resolve NestJS dist build and Prometheus target issues
NestJS: disable incremental in 6 services tsconfig.json to fix dist
not emitted when nest-cli deleteOutDir conflicts with tsc tsbuildinfo.
classes/iam: import HealthModule in AppModule to fix /healthz 404.
classes: rewrite HealthController to Drizzle getDb from TypeORM DI.
teacher-bff: add /metrics endpoint for Prometheus scraping.
infra: add node/mysql/redis exporters to observability profile.
mysql-exporter v0.15.1 uses command-line flags not DATA_SOURCE_NAME.
prometheus: enable web.enable-lifecycle for hot reload.
2026-07-09 15:12:15 +08:00

302 lines
12 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
Edu start all application services script
.DESCRIPTION
Starts 10 application services + 1 frontend (teacher-portal)
Each service runs in a separate terminal window for log visibility
Automatically injects Python service env vars (CLICKHOUSE/KAFKA/OTEL)
Prerequisite: infrastructure containers (MySQL/Redis/Kafka/ClickHouse etc) must be running
.PARAMETER SkipInfraCheck
Skip infrastructure health check (use when infra is known to be running)
.EXAMPLE
.\scripts\start-all.ps1
.\scripts\start-all.ps1 -SkipInfraCheck
#>
param(
[switch]$SkipInfraCheck,
[switch]$Force
)
$ErrorActionPreference = "Stop"
$ProjectRoot = Split-Path -Parent $PSScriptRoot
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Edu Start All Services" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# ===== 1. Infrastructure health check =====
if (-not $SkipInfraCheck) {
Write-Host "[1/6] Checking infrastructure health..." -ForegroundColor Yellow
$infraServices = @(
@{Name="MySQL"; Container="edu-mysql"},
@{Name="Redis"; Container="edu-redis"},
@{Name="Kafka"; Container="edu-kafka"},
@{Name="ClickHouse"; Container="edu-clickhouse"},
@{Name="Debezium"; Container="edu-debezium"},
@{Name="Jaeger"; Container="edu-jaeger"}
)
$allHealthy = $true
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue"
foreach ($svc in $infraServices) {
$running = docker inspect -f '{{.State.Running}}' $svc.Container 2>$null
if ($running -ne "true") {
Write-Host " [FAIL] $($svc.Name) not running" -ForegroundColor Red
$allHealthy = $false
continue
}
# 条件模板Health 不存在时返回空字符串,不报错
$health = docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' $svc.Container 2>$null
if ($health -eq "healthy") {
Write-Host " [OK] $($svc.Name) ($($svc.Container))" -ForegroundColor Green
} else {
Write-Host " [WARN] $($svc.Name) running (no healthcheck)" -ForegroundColor Yellow
}
}
$ErrorActionPreference = $prevEAP
if (-not $allHealthy) {
Write-Host ""
Write-Host "Infrastructure not ready. Start it first:" -ForegroundColor Red
Write-Host " docker compose -f infra/docker-compose.yml --profile p6 --profile observability up -d" -ForegroundColor White
exit 1
}
Write-Host ""
}
# ===== 2. Environment variables =====
Write-Host "[2/6] Preparing environment variables..." -ForegroundColor Yellow
$env:DEV_MODE = "true"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"
$env:DATABASE_URL = "mysql://edu:changeme@localhost:3306/next_edu_cloud"
$env:REDIS_URL = "redis://localhost:6379"
$env:JWT_SECRET = "p1-dev-secret-change-in-production"
$env:KAFKA_BROKERS = "localhost:9092"
$pyEnv = @{
CLICKHOUSE_HOST = "localhost"
CLICKHOUSE_PORT = "8123"
CLICKHOUSE_USER = "default"
CLICKHOUSE_PASSWORD = "clickhouse"
CLICKHOUSE_DATABASE = "edu_analytics"
KAFKA_BROKERS = "localhost:9092"
OTEL_ENDPOINT = "http://localhost:4318"
DEV_MODE = "true"
}
Write-Host " DEV_MODE=true (dev-token bypass)" -ForegroundColor Green
Write-Host " OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318" -ForegroundColor Green
Write-Host ""
# ===== 3. Port conflict check =====
Write-Host "[3/6] Checking port conflicts..." -ForegroundColor Yellow
$portMap = @{
3001="classes"; 3002="iam"; 3003="teacher-bff"; 3004="core-edu"
3005="content"; 3006="data-ana"; 3007="msg"; 3008="ai"
8080="api-gateway"; 8081="push-gateway"; 3000="teacher-portal"
}
$conflicts = @()
foreach ($port in $portMap.Keys | Sort-Object) {
$conn = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
if ($conn) {
$svcName = $portMap[$port]
$procId = $conn[0].OwningProcess
$procName = ""
try { $procName = (Get-Process -Id $procId -ErrorAction Stop).ProcessName } catch {}
Write-Host " [WARN] Port $port ($svcName) occupied by PID $procId ($procName)" -ForegroundColor Yellow
$conflicts += [PSCustomObject]@{Port=$port; Service=$svcName; PID=$procId; Process=$procName}
}
}
if ($conflicts.Count -gt 0) {
Write-Host ""
Write-Host " $($conflicts.Count) port(s) already in use." -ForegroundColor Yellow
$shouldKill = $false
if ($Force) {
Write-Host " -Force specified, killing automatically..." -ForegroundColor White
$shouldKill = $true
} else {
Write-Host " These services may already be running. Options:" -ForegroundColor White
Write-Host " 1. Run .\scripts\stop-all.ps1 -KillByPort first, then re-run start-all" -ForegroundColor White
Write-Host " 2. Re-run with -Force to auto-kill and continue" -ForegroundColor White
Write-Host ""
$answer = Read-Host " Kill existing processes and continue? (y/N)"
if ($answer -eq "y" -or $answer -eq "Y") {
$shouldKill = $true
}
}
if ($shouldKill) {
foreach ($c in $conflicts) {
try {
Stop-Process -Id $c.PID -Force -ErrorAction Stop
Write-Host " [OK] Killed PID $($c.PID) ($($c.Process)) on port $($c.Port)" -ForegroundColor Green
Start-Sleep -Milliseconds 500
} catch {
Write-Host " [WARN] Cannot kill PID $($c.PID): $($_.Exception.Message)" -ForegroundColor Yellow
}
}
Start-Sleep -Seconds 2
} else {
Write-Host " Aborting. Please stop existing services first." -ForegroundColor Red
exit 1
}
} else {
Write-Host " [OK] All app ports are free" -ForegroundColor Green
}
Write-Host ""
# ===== 4. Build NestJS services (required for nest start --watch) =====
Write-Host "[4/6] Building NestJS services (first time required)..." -ForegroundColor Yellow
$nestjsServices = @(
"@edu/classes-service",
"@edu/iam-service",
"@edu/teacher-bff",
"@edu/core-edu-service",
"@edu/content-service",
"@edu/msg-service"
)
# Clean tsbuildinfo cache (incremental mode leftover causes tsc to skip emit)
$nestjsDirs = @("classes", "iam", "teacher-bff", "core-edu", "content", "msg")
foreach ($dir in $nestjsDirs) {
$svcPath = Join-Path $ProjectRoot "services\$dir"
if (Test-Path $svcPath) {
Get-ChildItem -Path $svcPath -Filter "*.tsbuildinfo" -Recurse -ErrorAction SilentlyContinue |
Remove-Item -Force -ErrorAction SilentlyContinue
}
}
foreach ($svc in $nestjsServices) {
Write-Host " Building $svc..." -ForegroundColor Gray -NoNewline
$buildResult = pnpm --filter $svc build 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK]" -ForegroundColor Green
} else {
Write-Host " [FAIL]" -ForegroundColor Red
Write-Host " $buildResult" -ForegroundColor DarkGray
}
}
Write-Host ""
# ===== 5. Start application services =====
Write-Host "[5/6] Starting application services (11 windows)..." -ForegroundColor Yellow
$services = @(
@{Title="edu-app-classes"; Cmd="pnpm"; Args=@("--filter","@edu/classes-service","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-iam"; Cmd="pnpm"; Args=@("--filter","@edu/iam-service","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-teacher-bff"; Cmd="pnpm"; Args=@("--filter","@edu/teacher-bff","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-core-edu"; Cmd="pnpm"; Args=@("--filter","@edu/core-edu-service","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-content"; Cmd="pnpm"; Args=@("--filter","@edu/content-service","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-msg"; Cmd="pnpm"; Args=@("--filter","@edu/msg-service","dev"); Dir="$ProjectRoot"},
@{Title="edu-app-data-ana"; Cmd="uv"; Args=@("run","uvicorn","data_ana.main:app","--app-dir","src","--host","0.0.0.0","--port","3006","--reload"); Dir="$ProjectRoot\services\data-ana"; PyEnv=$true},
@{Title="edu-app-ai"; Cmd="uv"; Args=@("run","uvicorn","ai.main:app","--app-dir","src","--host","0.0.0.0","--port","3008","--reload"); Dir="$ProjectRoot\services\ai"; PyEnv=$true},
@{Title="edu-app-api-gateway"; Cmd="go"; Args=@("run","."); Dir="$ProjectRoot\services\api-gateway"; GoEnv=$true},
@{Title="edu-app-push-gateway"; Cmd="go"; Args=@("run","."); Dir="$ProjectRoot\services\push-gateway";GoEnv=$true},
@{Title="edu-app-teacher-portal";Cmd="pnpm";Args=@("--filter","teacher-portal","dev"); Dir="$ProjectRoot"}
)
foreach ($svc in $services) {
$cmdStr = "$($svc.Cmd) $($svc.Args -join ' ')"
$psCmd = "Set-Location '$($svc.Dir)'; "
if ($svc.PyEnv) {
foreach ($kv in $pyEnv.GetEnumerator()) {
$psCmd += "`$env:$($kv.Key)='$($kv.Value)'; "
}
}
if ($svc.GoEnv) {
$psCmd += "`$env:Path = 'C:\Program Files\Go\bin;' + `$env:Path; "
}
$psCmd += "$cmdStr; Write-Host ''; Write-Host 'Service stopped. Press any key to close...' -ForegroundColor Yellow; `$null = `$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')"
Start-Process -FilePath "powershell" -ArgumentList "-NoExit","-Command",$psCmd -WindowStyle Normal | Out-Null
Write-Host " [START] $($svc.Title)..." -ForegroundColor Green
Start-Sleep -Milliseconds 500
}
Write-Host ""
Write-Host " All services started in new windows. Waiting 40s for init..." -ForegroundColor Yellow
Start-Sleep -Seconds 40
# ===== 6. Health check =====
Write-Host "[6/6] Health check..." -ForegroundColor Yellow
Write-Host ""
$healthServices = @(
@{Name="classes"; Url="http://localhost:3001/healthz"},
@{Name="iam"; Url="http://localhost:3002/healthz"},
@{Name="teacher-bff"; Url="http://localhost:3003/healthz"},
@{Name="core-edu"; Url="http://localhost:3004/healthz"},
@{Name="content"; Url="http://localhost:3005/healthz"},
@{Name="data-ana"; Url="http://localhost:3006/healthz"},
@{Name="msg"; Url="http://localhost:3007/healthz"},
@{Name="ai"; Url="http://localhost:3008/healthz"},
@{Name="api-gateway"; Url="http://localhost:8080/healthz"},
@{Name="push-gateway"; Url="http://localhost:8081/healthz"},
@{Name="teacher-portal";Url="http://localhost:3000/"}
)
$okCount = 0
$failCount = 0
$failedServices = @()
foreach ($svc in $healthServices) {
$retries = 0
$maxRetries = 3
$success = $false
$lastError = ""
while ($retries -lt $maxRetries -and -not $success) {
try {
$null = Invoke-RestMethod -Uri $svc.Url -Method Get -TimeoutSec 5 -ErrorAction Stop
Write-Host " [OK] $($svc.Name)" -ForegroundColor Green
$success = $true
$okCount++
} catch {
$lastError = $_.Exception.Message
$retries++
if ($retries -lt $maxRetries) {
Start-Sleep -Seconds 5
}
}
}
if (-not $success) {
Write-Host " [FAIL] $($svc.Name) (after $maxRetries retries: $lastError)" -ForegroundColor Red
$failCount++
$failedServices += $svc.Name
}
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Started: [OK] $okCount ready / [FAIL] $failCount failed" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
if ($failCount -gt 0) {
Write-Host ""
Write-Host "Failed services: $($failedServices -join ', ')" -ForegroundColor Red
Write-Host ""
Write-Host "Troubleshooting:" -ForegroundColor Yellow
Write-Host " 1. Check the service window for error output" -ForegroundColor White
Write-Host " 2. Verify dependencies: pnpm install / uv sync / go mod tidy" -ForegroundColor White
Write-Host " 3. Re-run health check: .\scripts\health-check.ps1" -ForegroundColor White
Write-Host " 4. Stop and retry: .\scripts\stop-all.ps1 -KillByPort then .\scripts\start-all.ps1" -ForegroundColor White
Write-Host ""
exit 1
}
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host " Health check: .\scripts\health-check.ps1" -ForegroundColor White
Write-Host " CDC test: .\scripts\test-cdc.ps1" -ForegroundColor White
Write-Host " Stop all: .\scripts\stop-all.ps1" -ForegroundColor White
Write-Host ""