diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-17 12:46:13 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-17 12:46:13 -0700 |
| commit | 1482422f2f5b236cdcdff4429ae06bb55dca4083 (patch) | |
| tree | 4653cb4986a8a138f84dbec934effb0d011751d3 /scripts | |
Add stack start and stop scripts
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/start-stack.sh | 80 | ||||
| -rwxr-xr-x | scripts/stop-stack.sh | 42 |
2 files changed, 122 insertions, 0 deletions
diff --git a/scripts/start-stack.sh b/scripts/start-stack.sh new file mode 100755 index 0000000..6324967 --- /dev/null +++ b/scripts/start-stack.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +RUN_DIR="$ROOT_DIR/.run" +LOG_DIR="$RUN_DIR/logs" + +BACKEND_PID_FILE="$RUN_DIR/backend.pid" +FRONTEND_PID_FILE="$RUN_DIR/frontend.pid" +BACKEND_LOG="$LOG_DIR/backend.log" +FRONTEND_LOG="$LOG_DIR/frontend.log" + +BACKEND_HOST="${BACKEND_HOST:-127.0.0.1}" +BACKEND_PORT="${BACKEND_PORT:-8001}" +FRONTEND_HOST="${FRONTEND_HOST:-127.0.0.1}" +FRONTEND_PORT="${FRONTEND_PORT:-3001}" +API_BASE_URL="${NEXT_PUBLIC_API_BASE_URL:-http://${BACKEND_HOST}:${BACKEND_PORT}}" + +mkdir -p "$LOG_DIR" + +is_running() { + local pid_file="$1" + if [[ -f "$pid_file" ]]; then + local pid + pid="$(cat "$pid_file")" + if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then + return 0 + fi + rm -f "$pid_file" + fi + return 1 +} + +require_file() { + local path="$1" + local label="$2" + if [[ ! -e "$path" ]]; then + echo "$label not found: $path" >&2 + exit 1 + fi +} + +require_file "$ROOT_DIR/backend/.venv/bin/uvicorn" "Backend virtualenv executable" +require_file "$ROOT_DIR/frontend/node_modules" "Frontend dependencies" + +if is_running "$BACKEND_PID_FILE"; then + echo "Backend already running on PID $(cat "$BACKEND_PID_FILE")" +else + ( + cd "$ROOT_DIR/backend" + exec .venv/bin/uvicorn app.main:app --reload --host "$BACKEND_HOST" --port "$BACKEND_PORT" + ) >"$BACKEND_LOG" 2>&1 & + echo $! >"$BACKEND_PID_FILE" + echo "Started backend on http://${BACKEND_HOST}:${BACKEND_PORT} (PID $(cat "$BACKEND_PID_FILE"))" +fi + +if is_running "$FRONTEND_PID_FILE"; then + echo "Frontend already running on PID $(cat "$FRONTEND_PID_FILE")" +else + ( + cd "$ROOT_DIR/frontend" + export NEXT_PUBLIC_API_BASE_URL="$API_BASE_URL" + exec npm run dev -- --hostname "$FRONTEND_HOST" --port "$FRONTEND_PORT" + ) >"$FRONTEND_LOG" 2>&1 & + echo $! >"$FRONTEND_PID_FILE" + echo "Started frontend on http://${FRONTEND_HOST}:${FRONTEND_PORT} (PID $(cat "$FRONTEND_PID_FILE"))" +fi + +cat <<EOF + +Stack status +- Frontend: http://${FRONTEND_HOST}:${FRONTEND_PORT} +- Backend: http://${BACKEND_HOST}:${BACKEND_PORT} +- API base: $API_BASE_URL +- Logs: $LOG_DIR + +Stop both services with: + ./scripts/stop-stack.sh +EOF diff --git a/scripts/stop-stack.sh b/scripts/stop-stack.sh new file mode 100755 index 0000000..606de01 --- /dev/null +++ b/scripts/stop-stack.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +RUN_DIR="$ROOT_DIR/.run" + +BACKEND_PID_FILE="$RUN_DIR/backend.pid" +FRONTEND_PID_FILE="$RUN_DIR/frontend.pid" + +stop_process() { + local name="$1" + local pid_file="$2" + if [[ ! -f "$pid_file" ]]; then + echo "$name not running" + return + fi + + local pid + pid="$(cat "$pid_file")" + + if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + for _ in {1..20}; do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + sleep 0.25 + done + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + fi + echo "Stopped $name (PID $pid)" + else + echo "$name pid file was stale" + fi + + rm -f "$pid_file" +} + +stop_process "frontend" "$FRONTEND_PID_FILE" +stop_process "backend" "$BACKEND_PID_FILE" |
