<# .SYNOPSIS Edu v2.1 一键关闭脚本 .DESCRIPTION 关闭顺序: 1. 关闭 Apollo Router Docker 容器(避免子图关闭时 router 报错) 2. 关闭应用服务窗口(edu-app-* 标题匹配) 3. 按端口杀残留进程(可选 -KillByPort) 4. 关闭 Docker 基础设施(可选 -IncludeDocker) .PARAMETER KillByPort 按端口强制杀进程(窗口关闭后进程残留时使用) .PARAMETER IncludeDocker 同时关闭 Docker 基础设施容器 .PARAMETER SkipRouter 跳过 Apollo Router 容器关闭 .EXAMPLE .\scripts\stop-all.ps1 # 关闭应用服务 + Router .\scripts\stop-all.ps1 -KillByPort # 强制杀端口进程 .\scripts\stop-all.ps1 -IncludeDocker # 关闭应用 + Router + Docker .\scripts\stop-all.ps1 -KillByPort -IncludeDocker # 全部关闭 #> param( [switch]$KillByPort, [switch]$IncludeDocker, [switch]$SkipRouter ) $ErrorActionPreference = "Continue" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Edu v2.1 Stop All Services" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" # ===== 0. 关闭 Apollo Router 容器 ===== # 先关闭 router,避免子图关闭时 router 报连接错误刷日志 if (-not $SkipRouter) { Write-Host "[0/3] Stopping Apollo Router container..." -ForegroundColor Yellow $routerRunning = docker inspect -f '{{.State.Running}}' edu-apollo-router 2>$null if ($routerRunning -eq "true") { docker rm -f edu-apollo-router 2>&1 | Out-Null Write-Host " [OK] edu-apollo-router removed" -ForegroundColor Green } else { Write-Host " [--] edu-apollo-router not running" -ForegroundColor Gray } Write-Host "" } else { Write-Host "[0/3] Skipping Apollo Router (-SkipRouter)" -ForegroundColor Gray Write-Host "" } # ===== 1. 关闭应用服务窗口 ===== Write-Host "[1/3] Closing app service windows..." -ForegroundColor Yellow $appTitles = @( "edu-app-iam", "edu-app-config-service", "edu-app-classes", "edu-app-core-edu", "edu-app-content", "edu-app-msg", "edu-app-data-ana", "edu-app-ai", "edu-app-api-gateway", "edu-app-push-gateway", "edu-app-portal-shell" ) $closedCount = 0 foreach ($title in $appTitles) { $procs = Get-Process -Name "powershell","pwsh","node","python","uvicorn","go" -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowTitle -like "*$title*" } if ($procs) { foreach ($p in $procs) { try { Stop-Process -Id $p.Id -Force -ErrorAction Stop Write-Host " [OK] Closed $title (PID $($p.Id))" -ForegroundColor Green $closedCount++ } catch { Write-Host " [WARN] Cannot close $title (PID $($p.Id)): $($_.Exception.Message)" -ForegroundColor Yellow } } } else { Write-Host " [--] $title window not found" -ForegroundColor Gray } } Write-Host "" Write-Host " Closed $closedCount windows" -ForegroundColor Green Write-Host "" # ===== 2. 按端口杀残留进程 ===== if ($KillByPort) { Write-Host "[2/3] Killing processes by port..." -ForegroundColor Yellow $ports = @(3000,3001,3002,3004,3005,3006,3007,3008,3011,8080,8081,4010,50052,50053,50054,50055,50056,50058,50059) foreach ($port in $ports) { $connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue if ($connections) { foreach ($conn in $connections) { try { $proc = Get-Process -Id $conn.OwningProcess -ErrorAction Stop Stop-Process -Id $conn.OwningProcess -Force -ErrorAction Stop Write-Host " [OK] Port $port -> killed $($proc.ProcessName) (PID $($conn.OwningProcess))" -ForegroundColor Green } catch { Write-Host " [WARN] Port $port -> cannot kill PID $($conn.OwningProcess)" -ForegroundColor Yellow } } } else { Write-Host " [--] Port $port free" -ForegroundColor Gray } } } else { Write-Host "[2/3] Skipping port kill (use -KillByPort to enable)" -ForegroundColor Gray } Write-Host "" # ===== 3. 关闭 Docker 基础设施 ===== if ($IncludeDocker) { Write-Host "[3/3] Stopping Docker infrastructure..." -ForegroundColor Yellow $ProjectRoot = Split-Path -Parent $PSScriptRoot Push-Location "$ProjectRoot\infra" try { # 停止所有 profile 的所有容器(包括可能存在的 app 容器) docker compose -f docker-compose.yml --profile p3 --profile p5 --profile observability down 2>&1 | Out-Host Write-Host " [OK] Docker containers stopped" -ForegroundColor Green } catch { Write-Host " [WARN] $_" -ForegroundColor Yellow } Pop-Location } else { Write-Host "[3/3] Skipping Docker (-IncludeDocker to enable)" -ForegroundColor Gray } Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Stop complete" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan if (-not $IncludeDocker) { Write-Host "" Write-Host "To stop Docker infrastructure:" -ForegroundColor Yellow Write-Host " .\scripts\stop-all.ps1 -IncludeDocker" -ForegroundColor White Write-Host " or: docker compose -f infra/docker-compose.yml --profile p6 --profile observability down" -ForegroundColor White } Write-Host ""