From 0a6fa2a6566a6d20b9cd587f1d188869971871c5 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Tue, 19 May 2026 00:39:59 -0700 Subject: systemd --- scripts/stack.sh | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 scripts/stack.sh (limited to 'scripts/stack.sh') diff --git a/scripts/stack.sh b/scripts/stack.sh new file mode 100755 index 0000000..83f3920 --- /dev/null +++ b/scripts/stack.sh @@ -0,0 +1,142 @@ +#!/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}}" + +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 +} + +cmd_start() { + require_file "$ROOT_DIR/backend/.venv/bin/uvicorn" "Backend virtualenv executable" + require_file "$ROOT_DIR/frontend/node_modules" "Frontend dependencies" + mkdir -p "$LOG_DIR" + + 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 </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" +} + +cmd_stop() { + stop_process "frontend" "$FRONTEND_PID_FILE" + stop_process "backend" "$BACKEND_PID_FILE" +} + +cmd_restart() { + cmd_stop + cmd_start +} + +cmd_status() { + if is_running "$BACKEND_PID_FILE"; then + echo "backend running PID $(cat "$BACKEND_PID_FILE") http://${BACKEND_HOST}:${BACKEND_PORT}" + else + echo "backend stopped" + fi + + if is_running "$FRONTEND_PID_FILE"; then + echo "frontend running PID $(cat "$FRONTEND_PID_FILE") http://${FRONTEND_HOST}:${FRONTEND_PORT}" + else + echo "frontend stopped" + fi +} + +case "${1:-}" in + start) cmd_start ;; + stop) cmd_stop ;; + restart) cmd_restart ;; + status) cmd_status ;; + *) + echo "Usage: $(basename "$0") {start|stop|restart|status}" >&2 + exit 1 + ;; +esac -- cgit v1.3-2-g0d8e