#!/usr/bin/env bash # Launch AAO in gateway mode (OpenAI-compatible LLM gateway, no UI). # # This is a sibling of scripts/server.sh (worker mode). Both can run # concurrently on the same host because: # - PID file: .gateway.pid (worker uses .server.pid) # - Log file: logs/gateway.log (worker uses logs/server.log) # - Listen port: $GATEWAY_PORT (default 4000)、worker は $PORT (default 9876) # - DB: 同じ data/aao.db を SQLite WAL mode で共有 # (gateway は gateway_virtual_keys + gateway_key_usage の 2 table のみ touch) # # Usage: # scripts/gateway.sh start # scripts/gateway.sh stop # scripts/gateway.sh restart # scripts/gateway.sh status # scripts/gateway.sh logs # # Env override: # GATEWAY_PORT=4000 # gateway.listen_port を上書き (config.yaml より優先) # AAO_CONFIG=/etc/aao/config-gateway.yaml # 専用 config を使う場合 # AAO_GATEWAY_NO_DB=1 # ステートレス起動 (virtual_keys は config 経由のみ、budget/rate-limit 無効) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" PID_FILE="$PROJECT_DIR/.gateway.pid" LOG_FILE="$PROJECT_DIR/logs/gateway.log" GATEWAY_PORT="${GATEWAY_PORT:-4000}" cd "$PROJECT_DIR" usage() { echo "Usage: $0 {start|stop|restart|status|logs}" echo echo "Env:" echo " GATEWAY_PORT=$GATEWAY_PORT" echo " AAO_CONFIG=${AAO_CONFIG:-}" echo " AAO_GATEWAY_NO_DB=${AAO_GATEWAY_NO_DB:-}" exit 1 } is_running() { if [[ -f "$PID_FILE" ]]; then local pid pid=$(cat "$PID_FILE") if kill -0 "$pid" 2>/dev/null; then return 0 fi rm -f "$PID_FILE" fi return 1 } do_start() { if is_running; then echo "Gateway already running (PID $(cat "$PID_FILE"))" return 0 fi mkdir -p "$(dirname "$LOG_FILE")" echo "Checking runtime dependencies..." "$SCRIPT_DIR/prepare.sh" echo "Building..." npm run build --silent 2>&1 | tail -1 echo "Starting gateway on port $GATEWAY_PORT..." # AAO_MODE=gateway は src/main.ts の switch を gateway/bootstrap に向ける # GATEWAY_PORT は src/gateway/config.ts が config.yaml の listen_port を # env で上書きするためのキー (実装側で env > config の precedence)。 AAO_MODE=gateway \ GATEWAY_PORT="$GATEWAY_PORT" \ ${AAO_CONFIG:+AAO_CONFIG="$AAO_CONFIG"} \ ${AAO_GATEWAY_NO_DB:+AAO_GATEWAY_NO_DB="$AAO_GATEWAY_NO_DB"} \ nohup node dist/main.js >> "$LOG_FILE" 2>&1 & local pid=$! echo "$pid" > "$PID_FILE" # Wait briefly and verify it started sleep 2 if kill -0 "$pid" 2>/dev/null; then echo "Gateway started (PID $pid, log: $LOG_FILE)" echo " Health: curl http://localhost:$GATEWAY_PORT/health/liveness" echo " Metrics: curl http://localhost:$GATEWAY_PORT/metrics" else rm -f "$PID_FILE" echo "Gateway failed to start. Last 20 log lines:" tail -20 "$LOG_FILE" return 1 fi } do_stop() { if ! is_running; then echo "Gateway not running" # Also kill any stray process on the port local stray stray=$(lsof -ti:"$GATEWAY_PORT" 2>/dev/null || true) if [[ -n "$stray" ]]; then echo "Found stray process on port $GATEWAY_PORT (PID $stray), killing..." kill "$stray" 2>/dev/null || true fi return 0 fi local pid pid=$(cat "$PID_FILE") echo "Stopping gateway (PID $pid)..." # SIGTERM で graceful shutdown (gateway.shutdown_graceful_sec で SSE drain) kill "$pid" 2>/dev/null || true # Wait for graceful shutdown — gateway drain may take up to ~30s by default for i in {1..60}; do if ! kill -0 "$pid" 2>/dev/null; then rm -f "$PID_FILE" echo "Gateway stopped (graceful)" return 0 fi sleep 0.5 done # Force kill echo "Graceful shutdown timed out; force killing..." kill -9 "$pid" 2>/dev/null || true rm -f "$PID_FILE" echo "Gateway stopped (forced)" } do_status() { if is_running; then local pid pid=$(cat "$PID_FILE") echo "Gateway running (PID $pid, port $GATEWAY_PORT)" # Probe liveness for confirmation if curl -sS -o /dev/null -w "%{http_code}" "http://localhost:$GATEWAY_PORT/health/liveness" 2>/dev/null | grep -q 200; then echo " Liveness: OK" else echo " Liveness: NOT OK (process up but endpoint not responding)" fi else echo "Gateway not running" fi } do_logs() { if [[ -f "$LOG_FILE" ]]; then tail -f "$LOG_FILE" else echo "No log file found at $LOG_FILE" fi } case "${1:-}" in start) do_start ;; stop) do_stop ;; restart) do_stop; do_start ;; status) do_status ;; logs) do_logs ;; *) usage ;; esac