Andrey Epifancev 63f464dfae perf: стенд для профилирования (postgres, api, prod-сборка фронта)
Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:06:41 +04:00

93 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Стенд профилирования: up | migrate | bootstrap | api | web-build | web | smoke | down | all
set -euo pipefail
cd "$(dirname "$0")/.."
ROOT="$(pwd)"
PERF="$ROOT/perf"
RUN="$PERF/.run"
VENV="$PERF/.venv"
mkdir -p "$RUN"
export PERF_API="${PERF_API:-http://localhost:8000}"
export PERF_WEB="${PERF_WEB:-http://localhost:8080}"
export PERF_DB_DSN="${PERF_DB_DSN:-postgresql://perf:perf@localhost:55432/perf}"
export DATABASE_URL="postgresql+asyncpg://perf:perf@localhost:55432/perf"
export DEBUG=true
export npm_config_registry="${npm_config_registry:-https://registry.npmjs.org}"
venv() {
if [ ! -x "$VENV/bin/python" ]; then
python3.12 -m venv "$VENV"
"$VENV/bin/pip" install -q -r "$ROOT/api/requirements-dev.txt" -r "$PERF/requirements.txt"
fi
}
start_bg() { # name, workdir, cmd...
local name="$1" dir="$2"; shift 2
if [ -f "$RUN/$name.pid" ] && kill -0 "$(cat "$RUN/$name.pid")" 2>/dev/null; then
echo "$name уже запущен (pid $(cat "$RUN/$name.pid"))"; return
fi
(cd "$dir" && nohup "$@" >"$RUN/$name.log" 2>&1 & echo $! >"$RUN/$name.pid")
}
wait_http() { # url, tries
for _ in $(seq 1 "${2:-60}"); do
curl -fsS -o /dev/null "$1" 2>/dev/null && return 0
sleep 1
done
echo "не дождались $1" >&2; return 1
}
cmd="${1:-}"
case "$cmd" in
up)
docker compose -f "$PERF/docker-compose.yml" up -d pg
for _ in $(seq 1 60); do
docker exec perf-pg pg_isready -U perf -d perf >/dev/null 2>&1 && break
sleep 1
done
docker exec perf-pg pg_isready -U perf -d perf
;;
migrate)
venv
(cd "$ROOT/api" && "$VENV/bin/alembic" upgrade head)
;;
bootstrap)
venv
"$VENV/bin/python" "$PERF/stand/bootstrap.py"
;;
api)
venv
start_bg api "$ROOT/api" "$VENV/bin/python" run_server.py
wait_http "$PERF_API/healthz" 60
;;
web-build)
(cd "$ROOT/web" && npm ci && npx rsbuild build -c ../perf/web/rsbuild.perf.config.ts \
&& PERF_PROFILING=1 npx rsbuild build -c ../perf/web/rsbuild.perf.config.ts)
;;
web)
start_bg web "$ROOT/web" npx rsbuild preview -c ../perf/web/rsbuild.perf.config.ts
wait_http "$PERF_WEB/" 60
;;
smoke)
venv
"$VENV/bin/python" "$PERF/stand/smoke.py"
;;
down)
for n in web api; do
if [ -f "$RUN/$n.pid" ]; then
pkill -P "$(cat "$RUN/$n.pid")" 2>/dev/null || true
kill "$(cat "$RUN/$n.pid")" 2>/dev/null || true
rm -f "$RUN/$n.pid"
fi
done
docker compose -f "$PERF/docker-compose.yml" down
;;
all)
"$0" up; "$0" migrate; "$0" bootstrap; "$0" web-build; "$0" api; "$0" web; "$0" smoke
;;
*)
echo "usage: $0 up|migrate|bootstrap|api|web-build|web|smoke|down|all" >&2; exit 2
;;
esac