Files
dpb/deploy.bat
T

210 lines
6.5 KiB
Batchfile
Raw Normal View History

@echo off
chcp 65001 >nul
setlocal EnableDelayedExpansion
set "SCRIPT_DIR=%~dp0"
set "LOG_DIR=%SCRIPT_DIR%logs"
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
:: 后端需要的环境变量(Start-Process 会继承给子进程)
set "ENVIRONMENT=dev"
if "%1"=="" goto :show_help
if "%1"=="start" goto :start_all
if "%1"=="stop" goto :stop_all
if "%1"=="restart" goto :restart_all
if "%1"=="status" goto :check_status
if "%1"=="migrate" goto :migrate
if "%1"=="help" goto :show_help
if "%1"=="--help" goto :show_help
if "%1"=="-h" goto :show_help
echo [X] 未知参数: %1
goto :show_help
:show_help
echo 使用说明:
echo %~nx0 start - 启动所有服务
echo %~nx0 stop - 停止所有服务
echo %~nx0 restart - 重启所有服务
echo %~nx0 status - 检查服务状态
echo %~nx0 migrate - 同步 breeding 表缺失列(生成器改字段后)
echo.
echo 服务说明:
echo 后端服务 - FastAPI 后端 (端口: 5667)
echo 前端 Web - Vue 前端 (端口: 5666)
echo.
echo 日志位置:
echo %LOG_DIR%\
goto :end
:start_all
echo [>] 开始启动所有服务...
echo.
:: backend: 由系统计划任务服务托管,完全脱离用户会话/窗口,关闭 bat 窗口也不死
call :start_service "backend" "C:\ai\miniconda3\envs\dpb\python.exe" "-X utf8 -m uvicorn main:create_app --factory --host 0.0.0.0 --port 5667" "backend.log" "backend_err.log" "%SCRIPT_DIR%backend"
:: frontend: 同理由计划任务服务托管
call :start_service "frontend" "pnpm.cmd" "dev" "frontend.log" "frontend_err.log" "%SCRIPT_DIR%frontend\web"
echo.
echo [OK] 所有服务启动完成(由系统任务计划程序托管,关闭窗口/注销均不会停止)!
echo.
echo 访问地址:
echo 后端 API: http://localhost:5667/api/v1/docs
echo 前端 Web: http://localhost:5666/web/
echo.
goto :end
:start_service
set "NAME=%~1"
set "EXE=%~2"
set "ARGS=%~3"
set "OUT_LOG=%~4"
set "ERR_LOG=%~5"
set "WORKDIR=%~6"
set "TASK_NAME=dpb_%NAME%"
echo [~] 启动 %NAME% 服务...
:: 若同名任务已存在,先删除(保证干净重启)
schtasks /Query /TN "%TASK_NAME%" >nul 2>&1
if !errorlevel!==0 (
echo [!] %NAME% 任务已存在,先删除旧任务
schtasks /Delete /TN "%TASK_NAME%" /F >nul 2>&1
)
:: 先生成运行包装 cmd(路径无空格,无需内部引号):设工作目录 + ENVIRONMENT + 起 exe 重定向日志
set "RUN_WRAPPER=%LOG_DIR%\%NAME%_run.cmd"
(
echo @echo off
echo cd /d %WORKDIR%
echo set ENVIRONMENT=dev
echo "%EXE%" %ARGS% ^> "%LOG_DIR%\!OUT_LOG!" 2^> "%LOG_DIR%\!ERR_LOG!"
) > "%RUN_WRAPPER%"
:: 用 start /min 起独立进程(不挂当前 bat 窗口),bat 末尾会主动 exit,窗口关/退出都不影响进程
:: 记录 PID 供 stop 使用(start /min 不会新开可见窗口,进程由系统独立托管)
for /f "tokens=2 delims==; " %%p in ('wmic process call create CommandLine^="cmd /c \"%RUN_WRAPPER%\"" ^| findstr ProcessId') do (
echo %%p > "%LOG_DIR%\%NAME%.pid"
)
:: 后端加载慢(约20s),这里等一会;确切状态以用户访问为准
if "%NAME%"=="backend" ( ping -n 20 127.0.0.1 >nul ) else ( ping -n 6 127.0.0.1 >nul )
echo [OK] %NAME% 已启动 (PID 已写入 %LOG_DIR%\%NAME%.pid,日志: %LOG_DIR%\%OUT_LOG%)
cd /d "%SCRIPT_DIR%"
exit /b
:stop_all
echo [x] 开始停止所有服务...
echo.
call :stop_service "backend"
call :stop_service "frontend"
echo [OK] 所有服务已停止!
echo.
goto :end
:stop_service
set "NAME=%~1"
set "TASK_NAME=dpb_%NAME%"
set "PORT=0"
if "%NAME%"=="backend" set "PORT=5667"
if "%NAME%"=="frontend" set "PORT=5666"
echo [~] 停止 %NAME% 服务...
set "PID_FILE=%LOG_DIR%\%NAME%.pid"
:: 先按监听端口杀进程树(端口还 UP 时最准,连子进程一起杀)
if not "%PORT%"=="0" (
for /f "tokens=*" %%p in ('powershell -NoProfile -Command "(Get-NetTCPConnection -LocalPort %PORT% -State Listen -ErrorAction SilentlyContinue).OwningProcess -join ''"') do (
if not "%%p"=="" taskkill /PID %%p /T /F >nul 2>&1
)
)
:: 再按 pid 文件杀(兜底,处理端口已释放但进程残留)
if exist "%PID_FILE%" (
set /p PID=<"%PID_FILE%"
set "SAFE_KILL=0"
if "!PORT!"=="5667" (
powershell -NoProfile -Command "(Get-NetTCPConnection -LocalPort 5667 -State Listen -ErrorAction SilentlyContinue).OwningProcess -contains [int]!PID!" >nul 2>&1 && set "SAFE_KILL=1"
)
if "!PORT!"=="5666" (
powershell -NoProfile -Command "(Get-NetTCPConnection -LocalPort 5666 -State Listen -ErrorAction SilentlyContinue).OwningProcess -contains [int]!PID!" >nul 2>&1 && set "SAFE_KILL=1"
)
tasklist /FI "PID eq !PID!" 2>NUL | findstr /I "!PID!" >NUL
if !errorlevel!==0 (
if "!SAFE_KILL!"=="1" (
taskkill /PID !PID! /T /F >NUL 2>&1
) else (
echo [!] %NAME%: PID !PID! 未监听 dpb 端口,跳过(可能是其它项目进程,不杀)
)
)
del "%PID_FILE%" 2>NUL
) else (
echo [!] %NAME% 未在运行(无 PID 文件)
)
:stop_done
echo [OK] 已停止 %NAME%
exit /b
:restart_all
echo [~] 重启所有服务...
call :stop_all
echo.
call :start_all
goto :end
:check_status
echo [?] 检查服务状态...
echo.
call :check_service "backend"
call :check_service "frontend"
goto :end
:check_service
set "NAME=%~1"
set "PORT=0"
if "%NAME%"=="backend" set "PORT=5667"
if "%NAME%"=="frontend" set "PORT=5666"
set "PID_FILE=%LOG_DIR%\%NAME%.pid"
set "RUNNING=0"
if exist "%PID_FILE%" (
set /p PID=<"%PID_FILE%"
tasklist /FI "PID eq !PID!" 2>NUL | findstr /I "!PID!" >NUL
if !errorlevel!==0 set "RUNNING=1"
)
set "LISTENING=0"
for /f "tokens=*" %%p in ('powershell -NoProfile -Command "(Get-NetTCPConnection -LocalPort %PORT% -State Listen -ErrorAction SilentlyContinue).Count"') do (
if "%%p"=="1" set "LISTENING=1"
)
if %RUNNING%==1 (
if %LISTENING%==1 (
echo [OK] %NAME%: 运行中(PID 文件存在,端口 %PORT% 监听中)
) else (
echo [!] %NAME%: 进程在但端口 %PORT% 未监听(启动中或异常,看日志)
)
) else (
if %LISTENING%==1 (
echo [!] %NAME%: 端口 %PORT% 监听中,但无 PID 文件(可能是其它方式起的)
) else (
echo [X] %NAME%: 未启动
)
)
exit /b
:migrate
echo [~] 同步 breeding 表缺失列...
cd /d "%SCRIPT_DIR%backend"
set "ENVIRONMENT=dev"
uv run python scripts/fix_breeding_columns.py || "C:\ai\miniconda3\envs\dpb\python.exe" scripts/fix_breeding_columns.py
cd /d "%SCRIPT_DIR%"
echo [OK] 列同步完成
goto :end
:end
echo ========================================
endlocal
exit