优化启动脚本
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*/__pycache__
|
*/__pycache__
|
||||||
*.pyc
|
*.pyc
|
||||||
|
.claude
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
|
||||||
# 环境变量(含敏感信息,勿提交)
|
# 环境变量(含敏感信息,勿提交)
|
||||||
.env
|
.env
|
||||||
|
|||||||
+64
-22
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -eo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
cd "$ROOT_DIR"
|
cd "$ROOT_DIR"
|
||||||
@@ -8,20 +8,38 @@ PYTHON="$ROOT_DIR/.venv/bin/python"
|
|||||||
FRONTEND_DIR="$ROOT_DIR/web/frontend"
|
FRONTEND_DIR="$ROOT_DIR/web/frontend"
|
||||||
BACKEND_PORT=8000
|
BACKEND_PORT=8000
|
||||||
FRONTEND_PORT=5173
|
FRONTEND_PORT=5173
|
||||||
|
HEALTH_TIMEOUT=30 # 后端健康检查最长等待秒数
|
||||||
|
|
||||||
|
# ── 工具函数 ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||||
|
warn() { echo "[$(date '+%H:%M:%S')] ⚠️ $*" >&2; }
|
||||||
|
die() { echo "[$(date '+%H:%M:%S')] ❌ $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
check_port() {
|
||||||
|
if lsof -iTCP:"$1" -sTCP:LISTEN -P &>/dev/null; then
|
||||||
|
die "端口 $1 已被占用,请先释放或更改端口号(lsof -i :$1)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── 预检查 ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
check_port "$BACKEND_PORT"
|
||||||
|
check_port "$FRONTEND_PORT"
|
||||||
|
|
||||||
# 检查 Python 虚拟环境
|
|
||||||
if [ ! -f "$PYTHON" ]; then
|
if [ ! -f "$PYTHON" ]; then
|
||||||
echo "❌ 未找到 .venv,正在创建..."
|
log "未找到 .venv,正在创建..."
|
||||||
uv venv .venv
|
uv venv .venv
|
||||||
uv pip install -e .
|
uv pip install -e .
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 检查前端依赖
|
|
||||||
if [ ! -d "$FRONTEND_DIR/node_modules" ]; then
|
if [ ! -d "$FRONTEND_DIR/node_modules" ]; then
|
||||||
echo "❌ 前端依赖未安装,正在安装..."
|
log "前端依赖未安装,正在安装..."
|
||||||
cd "$FRONTEND_DIR" && npm install && cd "$ROOT_DIR"
|
(cd "$FRONTEND_DIR" && npm install)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── 启动信息 ──────────────────────────────────────────────
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
echo " 斗鱼批量登录 - Web 后台"
|
echo " 斗鱼批量登录 - Web 后台"
|
||||||
@@ -33,34 +51,58 @@ echo " 按 Ctrl+C 停止所有服务"
|
|||||||
echo "=============================="
|
echo "=============================="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 清理子进程
|
# ── 清理子进程 ────────────────────────────────────────────
|
||||||
|
|
||||||
|
PIDS=()
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "正在停止服务..."
|
log "正在停止服务..."
|
||||||
kill $BACKEND_PID $FRONTEND_PID 2>/dev/null
|
for pid in "${PIDS[@]}"; do
|
||||||
wait $BACKEND_PID $FRONTEND_PID 2>/dev/null
|
if kill -0 "$pid" 2>/dev/null; then
|
||||||
echo "已停止"
|
kill "$pid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for pid in "${PIDS[@]}"; do
|
||||||
|
wait "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
log "已停止"
|
||||||
}
|
}
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
# 启动后端
|
# ── 启动后端 ──────────────────────────────────────────────
|
||||||
echo "启动后端 (FastAPI :$BACKEND_PORT)..."
|
|
||||||
|
log "启动后端 (FastAPI :$BACKEND_PORT)..."
|
||||||
RELOAD_FLAG=""
|
RELOAD_FLAG=""
|
||||||
if [ "${UVICORN_RELOAD:-true}" = "true" ]; then
|
if [ "${UVICORN_RELOAD:-true}" = "true" ]; then
|
||||||
RELOAD_FLAG="--reload"
|
RELOAD_FLAG="--reload"
|
||||||
fi
|
fi
|
||||||
"$PYTHON" -m uvicorn web.backend.main:app --host 0.0.0.0 --port $BACKEND_PORT $RELOAD_FLAG &
|
"$PYTHON" -m uvicorn web.backend.main:app --host 0.0.0.0 --port "$BACKEND_PORT" $RELOAD_FLAG &
|
||||||
BACKEND_PID=$!
|
PIDS+=($!)
|
||||||
|
|
||||||
# 等后端就绪
|
# 等后端就绪(健康检查循环替代固定 sleep)
|
||||||
sleep 2
|
log "等待后端就绪(最多 ${HEALTH_TIMEOUT}s)..."
|
||||||
|
elapsed=0
|
||||||
|
while [ "$elapsed" -lt "$HEALTH_TIMEOUT" ]; do
|
||||||
|
if curl -sf "http://localhost:$BACKEND_PORT/docs" -o /dev/null 2>/dev/null; then
|
||||||
|
log "后端已就绪 ✓"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
elapsed=$((elapsed + 1))
|
||||||
|
done
|
||||||
|
if [ "$elapsed" -ge "$HEALTH_TIMEOUT" ]; then
|
||||||
|
warn "后端未在 ${HEALTH_TIMEOUT}s 内就绪,前端可能无法正常连接"
|
||||||
|
fi
|
||||||
|
|
||||||
# 启动前端
|
# ── 启动前端 ──────────────────────────────────────────────
|
||||||
echo "启动前端 (Vite :$FRONTEND_PORT)..."
|
|
||||||
|
log "启动前端 (Vite :$FRONTEND_PORT)..."
|
||||||
cd "$FRONTEND_DIR"
|
cd "$FRONTEND_DIR"
|
||||||
npm run dev -- --port $FRONTEND_PORT --host 0.0.0.0 &
|
npm run dev -- --port "$FRONTEND_PORT" --host 0.0.0.0 &
|
||||||
FRONTEND_PID=$!
|
PIDS+=($!)
|
||||||
cd "$ROOT_DIR"
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
# 等待子进程
|
# ── 等待子进程 ────────────────────────────────────────────
|
||||||
|
|
||||||
wait
|
wait
|
||||||
|
|||||||
@@ -38,8 +38,18 @@ export default function LoginTasksPage() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [batchId, setBatchId] = useState<string | null>(null);
|
const [batchId, setBatchId] = useState<string | null>(null);
|
||||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||||
const [concurrency, setConcurrency] = useState(3);
|
const [concurrency, setConcurrency] = useState(() => {
|
||||||
const [maxProxyRetries, setMaxProxyRetries] = useState(10);
|
const v = localStorage.getItem('login_concurrency');
|
||||||
|
return v ? Math.max(1, Math.min(10, Number(v) || 3)) : 3;
|
||||||
|
});
|
||||||
|
const [maxProxyRetries, setMaxProxyRetries] = useState(() => {
|
||||||
|
const v = localStorage.getItem('login_max_proxy_retries');
|
||||||
|
return v ? Math.max(0, Number(v) || 10) : 10;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 值变化时自动持久化
|
||||||
|
useEffect(() => { localStorage.setItem('login_concurrency', String(concurrency)); }, [concurrency]);
|
||||||
|
useEffect(() => { localStorage.setItem('login_max_proxy_retries', String(maxProxyRetries)); }, [maxProxyRetries]);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
|
||||||
const { logs, connected: wsConnected, connect: connectLogs } = useWebSocketLogs();
|
const { logs, connected: wsConnected, connect: connectLogs } = useWebSocketLogs();
|
||||||
const { can } = usePermissions();
|
const { can } = usePermissions();
|
||||||
|
|||||||
Reference in New Issue
Block a user