293 lines
9.0 KiB
PowerShell
293 lines
9.0 KiB
PowerShell
param(
|
||
[string]$Command = 'status'
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
$ProgressPreference = 'SilentlyContinue'
|
||
|
||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
$RootDir = (Resolve-Path $ScriptDir).Path
|
||
$EnvConfig = Join-Path $RootDir 'env_config.ps1'
|
||
if (Test-Path $EnvConfig) {
|
||
. $EnvConfig
|
||
Import-EnvFile -Path (Join-Path $RootDir '.env')
|
||
}
|
||
$PythonBin = Join-Path $RootDir '.venv-qwen35\Scripts\python.exe'
|
||
$GatewayRun = Join-Path $RootDir 'run_8080_toolhub_gateway.py'
|
||
$RuntimeDir = Join-Path $RootDir '.tmp\toolhub_gateway'
|
||
$PidFile = Join-Path $RuntimeDir 'gateway.pid'
|
||
$LogFile = Join-Path $RuntimeDir 'gateway.log'
|
||
$ErrLogFile = Join-Path $RuntimeDir 'gateway.err.log'
|
||
$ModelSwitch = Join-Path $RootDir 'switch_qwen35_webui.ps1'
|
||
|
||
$GatewayHost = if ($env:GATEWAY_HOST) { $env:GATEWAY_HOST } else { '127.0.0.1' }
|
||
$GatewayPort = if ($env:GATEWAY_PORT) { $env:GATEWAY_PORT } else { '8080' }
|
||
$BackendHost = if ($env:BACKEND_HOST) { $env:BACKEND_HOST } else { '127.0.0.1' }
|
||
$BackendPort = if ($env:BACKEND_PORT) { $env:BACKEND_PORT } else { '8081' }
|
||
$ThinkMode = if ($env:THINK_MODE) { $env:THINK_MODE } else { 'think-on' }
|
||
$BackendWaitHint = '.\start_8080_toolhub_stack.cmd logs'
|
||
$SpinnerFrameIntervalMs = 120
|
||
$SpinnerProbeIntervalMs = 1000
|
||
|
||
function Ensure-Dir {
|
||
param([string]$Path)
|
||
if (-not (Test-Path $Path)) {
|
||
New-Item -Path $Path -ItemType Directory -Force | Out-Null
|
||
}
|
||
}
|
||
|
||
function Test-GatewayRunning {
|
||
if (-not (Test-Path $PidFile)) {
|
||
return $false
|
||
}
|
||
$raw = Get-Content -Path $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1
|
||
$gatewayPid = 0
|
||
if (-not [int]::TryParse([string]$raw, [ref]$gatewayPid)) {
|
||
return $false
|
||
}
|
||
$proc = Get-Process -Id $gatewayPid -ErrorAction SilentlyContinue
|
||
return $null -ne $proc
|
||
}
|
||
|
||
function Test-GatewayReady {
|
||
try {
|
||
$null = Invoke-RestMethod -Uri "http://$GatewayHost`:$GatewayPort/gateway/health" -Method Get -TimeoutSec 2
|
||
return $true
|
||
} catch {
|
||
return $false
|
||
}
|
||
}
|
||
|
||
function Show-GatewayFailureLogs {
|
||
Write-Host '网关启动失败,最近日志如下:'
|
||
if (Test-Path $LogFile) {
|
||
Write-Host '=== 网关标准输出 ==='
|
||
Get-Content -Path $LogFile -Tail 120 -ErrorAction SilentlyContinue
|
||
}
|
||
if (Test-Path $ErrLogFile) {
|
||
Write-Host '=== 网关标准错误 ==='
|
||
Get-Content -Path $ErrLogFile -Tail 120 -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
|
||
function Write-SpinnerLine {
|
||
param(
|
||
[string]$Label,
|
||
[double]$Current,
|
||
[int]$Total,
|
||
[int]$Tick
|
||
)
|
||
$frames = @('|', '/', '-', '\')
|
||
$frame = $frames[$Tick % $frames.Count]
|
||
$currentText = [string][int][Math]::Floor($Current)
|
||
Write-Host -NoNewline "`r$Label $frame $currentText/$Total 秒"
|
||
}
|
||
|
||
function Complete-SpinnerLine {
|
||
Write-Host ''
|
||
}
|
||
|
||
function Stop-OrphanGatewayProcesses {
|
||
try {
|
||
$rootPattern = [regex]::Escape($RootDir)
|
||
$targets = Get-CimInstance Win32_Process -Filter "Name='python.exe'" -ErrorAction SilentlyContinue | Where-Object {
|
||
$cmd = [string]$_.CommandLine
|
||
$cmd -match 'run_8080_toolhub_gateway\.py' -and $cmd -match $rootPattern
|
||
}
|
||
foreach ($proc in $targets) {
|
||
if ($proc.ProcessId) {
|
||
Stop-Process -Id ([int]$proc.ProcessId) -Force -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
} catch {}
|
||
}
|
||
|
||
function Start-Backend {
|
||
if ($env:MODEL_KEY -and $env:MODEL_KEY -ne '9b') {
|
||
throw "当前交付包仅支持 MODEL_KEY=9b,收到: $($env:MODEL_KEY)"
|
||
}
|
||
$oldHost = $env:HOST
|
||
$oldPort = $env:PORT
|
||
try {
|
||
$env:HOST = $BackendHost
|
||
$env:PORT = $BackendPort
|
||
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch '9b' $ThinkMode
|
||
if ($LASTEXITCODE -ne 0) {
|
||
throw '后端启动失败,请先查看上面的直接原因'
|
||
}
|
||
} finally {
|
||
$env:HOST = $oldHost
|
||
$env:PORT = $oldPort
|
||
}
|
||
}
|
||
|
||
function Start-Gateway {
|
||
Ensure-Dir $RuntimeDir
|
||
Stop-OrphanGatewayProcesses
|
||
if (Test-GatewayRunning) {
|
||
Write-Host '网关状态: 已运行'
|
||
Write-Host "PID: $(Get-Content -Path $PidFile)"
|
||
return
|
||
}
|
||
if (-not (Test-Path $PythonBin)) {
|
||
throw "Python 环境不存在: $PythonBin"
|
||
}
|
||
|
||
$args = @(
|
||
$GatewayRun,
|
||
'--host', $GatewayHost,
|
||
'--port', $GatewayPort,
|
||
'--backend-base', "http://$BackendHost`:$BackendPort",
|
||
'--model-server', "http://$BackendHost`:$BackendPort/v1"
|
||
)
|
||
if (Test-Path $ErrLogFile) {
|
||
Remove-Item -Path $ErrLogFile -Force -ErrorAction SilentlyContinue
|
||
}
|
||
$oldWaitHint = $env:BACKEND_WAIT_HINT
|
||
try {
|
||
$env:BACKEND_WAIT_HINT = $BackendWaitHint
|
||
$proc = Start-Process -FilePath $PythonBin -ArgumentList $args -WindowStyle Hidden -RedirectStandardOutput $LogFile -RedirectStandardError $ErrLogFile -PassThru
|
||
} finally {
|
||
$env:BACKEND_WAIT_HINT = $oldWaitHint
|
||
}
|
||
Set-Content -Path $PidFile -Value $proc.Id -Encoding ascii
|
||
|
||
$timeoutSec = 60
|
||
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
|
||
$nextProbeMs = 0
|
||
$tick = 0
|
||
while ($stopwatch.Elapsed.TotalSeconds -lt $timeoutSec) {
|
||
Write-SpinnerLine -Label '网关启动中...' -Current $stopwatch.Elapsed.TotalSeconds -Total $timeoutSec -Tick $tick
|
||
if ($stopwatch.ElapsedMilliseconds -ge $nextProbeMs) {
|
||
if (-not (Test-GatewayRunning)) {
|
||
break
|
||
}
|
||
if (Test-GatewayReady) {
|
||
Complete-SpinnerLine
|
||
return
|
||
}
|
||
$nextProbeMs += $SpinnerProbeIntervalMs
|
||
}
|
||
Start-Sleep -Milliseconds $SpinnerFrameIntervalMs
|
||
$tick++
|
||
}
|
||
Complete-SpinnerLine
|
||
|
||
Show-GatewayFailureLogs
|
||
throw '网关启动失败。'
|
||
}
|
||
|
||
function Stop-Gateway {
|
||
Stop-OrphanGatewayProcesses
|
||
if (-not (Test-GatewayRunning)) {
|
||
if (Test-Path $PidFile) {
|
||
Remove-Item -Path $PidFile -Force -ErrorAction SilentlyContinue
|
||
}
|
||
Write-Host '网关状态: 未运行'
|
||
return
|
||
}
|
||
|
||
$gatewayPid = [int](Get-Content -Path $PidFile | Select-Object -First 1)
|
||
Stop-Process -Id $gatewayPid -Force -ErrorAction SilentlyContinue
|
||
Start-Sleep -Seconds 1
|
||
if (Test-Path $PidFile) {
|
||
Remove-Item -Path $PidFile -Force -ErrorAction SilentlyContinue
|
||
}
|
||
Write-Host '网关状态: 已停止'
|
||
}
|
||
|
||
function Show-Status {
|
||
Write-Host '=== 网关 ==='
|
||
if (Test-GatewayRunning) {
|
||
$state = if (Test-GatewayReady) { '可访问' } else { '初始化中' }
|
||
Write-Host '状态: 运行中'
|
||
Write-Host "PID: $(Get-Content -Path $PidFile)"
|
||
Write-Host "地址: http://$GatewayHost`:$GatewayPort"
|
||
Write-Host "健康: $state"
|
||
Write-Host "日志: $LogFile"
|
||
Write-Host "错误日志: $ErrLogFile"
|
||
} else {
|
||
Write-Host '状态: 未运行'
|
||
}
|
||
|
||
Write-Host ''
|
||
Write-Host '=== 模型后端 ==='
|
||
$oldHost = $env:HOST
|
||
$oldPort = $env:PORT
|
||
try {
|
||
$env:HOST = $BackendHost
|
||
$env:PORT = $BackendPort
|
||
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch 'status'
|
||
} finally {
|
||
$env:HOST = $oldHost
|
||
$env:PORT = $oldPort
|
||
}
|
||
}
|
||
|
||
function Show-Logs {
|
||
Write-Host '=== 网关日志 ==='
|
||
if (Test-Path $LogFile) {
|
||
Get-Content -Path $LogFile -Tail 120
|
||
}
|
||
if (Test-Path $ErrLogFile) {
|
||
Write-Host '=== 网关错误日志 ==='
|
||
Get-Content -Path $ErrLogFile -Tail 120
|
||
return
|
||
}
|
||
Write-Host '暂无日志'
|
||
}
|
||
|
||
function Stop-Backend {
|
||
$oldHost = $env:HOST
|
||
$oldPort = $env:PORT
|
||
try {
|
||
$env:HOST = $BackendHost
|
||
$env:PORT = $BackendPort
|
||
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch 'stop'
|
||
} finally {
|
||
$env:HOST = $oldHost
|
||
$env:PORT = $oldPort
|
||
}
|
||
}
|
||
|
||
function Start-Stack {
|
||
try {
|
||
Write-Host '步骤 1/2: 启动模型后端'
|
||
Start-Backend
|
||
Write-Host '步骤 2/2: 启动网关服务'
|
||
Start-Gateway
|
||
Write-Host '栈已启动'
|
||
Write-Host "网页入口: http://$GatewayHost`:$GatewayPort"
|
||
Write-Host '可用状态检查命令: .\start_8080_toolhub_stack.cmd status'
|
||
Write-Host '停止命令: .\start_8080_toolhub_stack.cmd stop'
|
||
} catch {
|
||
Write-Host $_.Exception.Message
|
||
exit 1
|
||
}
|
||
}
|
||
|
||
function Stop-Stack {
|
||
Stop-Gateway
|
||
Stop-Backend
|
||
}
|
||
|
||
switch ($Command) {
|
||
'start' { Start-Stack; break }
|
||
'stop' { Stop-Stack; break }
|
||
'restart' { Stop-Stack; Start-Stack; break }
|
||
'status' { Show-Status; break }
|
||
'logs' { Show-Logs; break }
|
||
default {
|
||
Write-Host '用法:'
|
||
Write-Host ' .\\start_8080_toolhub_stack.cmd {start|stop|restart|status|logs}'
|
||
Write-Host ''
|
||
Write-Host '可选环境变量:'
|
||
Write-Host ' GATEWAY_HOST=127.0.0.1'
|
||
Write-Host ' GATEWAY_PORT=8080'
|
||
Write-Host ' BACKEND_HOST=127.0.0.1'
|
||
Write-Host ' BACKEND_PORT=8081'
|
||
Write-Host ' THINK_MODE=think-on'
|
||
exit 1
|
||
}
|
||
}
|