first
This commit is contained in:
Executable
+225
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env bash
|
||||
# start-stack.sh — avvia ASF Core, ASF Web (Next.js), e opzionalmente ASF Worker.
|
||||
# Usage:
|
||||
# ./scripts/start-stack.sh # core + web, reload + dev mode
|
||||
# ./scripts/start-stack.sh --no-reload # core senza --reload (productionish)
|
||||
# ./scripts/start-stack.sh --with-worker # avvia anche asf-worker (7 code)
|
||||
# ./scripts/start-stack.sh --web-only # solo frontend Next.js
|
||||
# ./scripts/start-stack.sh --core-only # solo backend Core (FastAPI)
|
||||
# Bindings default: 0.0.0.0 (core 8000, web 3000).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
usage() {
|
||||
sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage
|
||||
|
||||
WITH_WORKER=0
|
||||
RELOAD=1
|
||||
CORE=1
|
||||
WEB=1
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--with-worker|-w) WITH_WORKER=1 ;;
|
||||
--no-reload) RELOAD=0 ;;
|
||||
--web-only) CORE=0; WITH_WORKER=0 ;;
|
||||
--core-only) WEB=0 ;;
|
||||
-h|--help) usage ;;
|
||||
*) echo "Unknown option: $arg"; usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 1) Preflight checks
|
||||
# ------------------------------------------------------------
|
||||
VENV_DIR="$ROOT_DIR/.venv"
|
||||
if [ ! -d "$VENV_DIR" ]; then
|
||||
echo "[start-stack] ❌ .venv non trovata in $VENV_DIR. Crea prima la venv: python -m venv .venv && source .venv/bin/activate" >&2
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck disable=SC1091
|
||||
source "$VENV_DIR/bin/activate"
|
||||
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "[start-stack] ⚠️ .env non trovato, uso .env.example (se esiste)."
|
||||
if [ -f "$ROOT_DIR/.env.example" ]; then
|
||||
cp "$ROOT_DIR/.env.example" "$ROOT_DIR/.env"
|
||||
fi
|
||||
fi
|
||||
# shellcheck disable=SC1090
|
||||
set -a; [ -f "$ENV_FILE" ] && source "$ENV_FILE"; set +a
|
||||
|
||||
export ASF_ROOT="$ROOT_DIR"
|
||||
export PYTHONPATH="\
|
||||
$ROOT_DIR/packages/asf-domain:\
|
||||
$ROOT_DIR/services/asf-events:\
|
||||
$ROOT_DIR/services/asf-connectors:\
|
||||
$ROOT_DIR/services/asf-core:\
|
||||
$ROOT_DIR/services/asf-worker:\
|
||||
$ROOT_DIR/services/asf-ai:\
|
||||
$ROOT_DIR/services/asf-context\
|
||||
${PYTHONPATH:+:$PYTHONPATH}"
|
||||
|
||||
export NEXT_PUBLIC_ASF_CORE_URL="${NEXT_PUBLIC_ASF_CORE_URL:-http://localhost:8000}"
|
||||
export NEXT_PUBLIC_DEV_TENANT_ID="${NEXT_PUBLIC_DEV_TENANT_ID:-t-demo-001}"
|
||||
export NEXT_PUBLIC_DEV_USER_ID="${NEXT_PUBLIC_DEV_USER_ID:-u-admin}"
|
||||
|
||||
LOG_DIR="$ROOT_DIR/var/log/asf"
|
||||
PID_DIR="$ROOT_DIR/var/run"
|
||||
mkdir -p "$LOG_DIR" "$PID_DIR"
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 2) Helpers
|
||||
# ------------------------------------------------------------
|
||||
pids=()
|
||||
names=()
|
||||
|
||||
start_in_dir() {
|
||||
local name="$1"; shift
|
||||
local dir="$1"; shift
|
||||
local log="$LOG_DIR/$name.log"
|
||||
echo " starting $name ($(basename "$dir")) ..."
|
||||
(
|
||||
cd "$dir"
|
||||
# shellcheck disable=SC2093
|
||||
exec "$@" >"$log" 2>&1
|
||||
) &
|
||||
local pid=$!
|
||||
pids+=("$pid")
|
||||
names+=("$name")
|
||||
echo " pid=$pid log=$log"
|
||||
}
|
||||
|
||||
print_header() {
|
||||
local COLS
|
||||
COLS=$(tput cols 2>/dev/null || echo 80)
|
||||
printf '═%.0s' $(seq 1 "$COLS"); echo
|
||||
printf " ASF local stack · %s · tenant=%s user=%s\n" \
|
||||
"$(date '+%F %T %Z')" \
|
||||
"$NEXT_PUBLIC_DEV_TENANT_ID" \
|
||||
"$NEXT_PUBLIC_DEV_USER_ID"
|
||||
printf '═%.0s' $(seq 1 "$COLS"); echo
|
||||
}
|
||||
|
||||
graceful_stop() {
|
||||
echo
|
||||
echo "[start-stack] SIGINT/SIGTERM received — stopping ${#pids[@]} processes (${names[*]})."
|
||||
for i in "${!pids[@]}"; do
|
||||
local pid="${pids[$i]}"
|
||||
local name="${names[$i]}"
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo " stopping $name (pid=$pid)"
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
# wait them out
|
||||
local waited=0
|
||||
while [ $waited -lt 10 ]; do
|
||||
local alive=0
|
||||
for pid in "${pids[@]}"; do kill -0 "$pid" 2>/dev/null && alive=1; done
|
||||
[ $alive -eq 0 ] && break
|
||||
sleep 1; waited=$((waited+1))
|
||||
done
|
||||
# force kill any stragglers
|
||||
for pid in "${pids[@]}"; do
|
||||
kill -0 "$pid" 2>/dev/null && { echo " force kill pid=$pid"; kill -9 "$pid" 2>/dev/null || true; }
|
||||
done
|
||||
echo "[start-stack] stopped."
|
||||
exit 0
|
||||
}
|
||||
trap graceful_stop INT TERM
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 3) Dependency quick liveness (Mongo + Rabbit — best effort)
|
||||
# ------------------------------------------------------------
|
||||
print_header
|
||||
echo "[start-stack] python=$(python -V 2>&1 | cut -d' ' -f2) node=$(node -v) npm=v$(npm -v 2>/dev/null)"
|
||||
echo "[start-stack] PYTHONPATH[0:80]=${PYTHONPATH:0:80}…"
|
||||
echo
|
||||
echo "[deps] Mongo / Rabbit best-effort reachability (5s timeout)…"
|
||||
python - <<PY 2>/dev/null || true
|
||||
import os,socket,time
|
||||
for host,port,name in [("172.19.40.102",27017,"Mongo rs0 PRIMARY"),("172.19.40.103",27017,"Mongo rs0 SEED"),("172.19.40.201",5672,"RabbitMQ AMQP"),("172.19.40.201",15672,"RabbitMQ HTTP mgmt")]:
|
||||
s=socket.socket(); s.settimeout(2)
|
||||
try:
|
||||
s.connect((host,port)); print(f" ✅ {name:22s} {host}:{port} reachable")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ {name:22s} {host}:{port} unreachable ({e})")
|
||||
finally: s.close()
|
||||
PY
|
||||
echo
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 4) Start processes
|
||||
# ------------------------------------------------------------
|
||||
echo "[start-stack] launching services (bind 0.0.0.0)…"
|
||||
|
||||
# Core (FastAPI)
|
||||
if [ $CORE -eq 1 ]; then
|
||||
CORE_ARGS=(uvicorn app.main:app --host 0.0.0.0 --port 8000)
|
||||
[ $RELOAD -eq 1 ] && CORE_ARGS+=(--reload)
|
||||
start_in_dir "asf-core" "$ROOT_DIR/services/asf-core" "${CORE_ARGS[@]}"
|
||||
echo " → http://0.0.0.0:8000/docs (OpenAPI)"
|
||||
fi
|
||||
|
||||
# Web (Next.js dev)
|
||||
if [ $WEB -eq 1 ]; then
|
||||
start_in_dir "asf-web" "$ROOT_DIR/frontend/asf-web" npm run dev -- --hostname 0.0.0.0 --port 3000
|
||||
echo " → http://0.0.0.0:3000 (UI)"
|
||||
fi
|
||||
|
||||
# Worker
|
||||
if [ $WITH_WORKER -eq 1 ]; then
|
||||
start_in_dir "asf-worker" "$ROOT_DIR/services/asf-worker" python -m app.worker
|
||||
echo " → queues=$ASF_WORKER_JOB_QUEUES"
|
||||
fi
|
||||
|
||||
echo
|
||||
# Save PIDs on disk for `stop-stack.sh`
|
||||
: > "$PID_DIR/asf-stack.pids"
|
||||
for i in "${!pids[@]}"; do
|
||||
echo "${names[$i]} ${pids[$i]}" >> "$PID_DIR/asf-stack.pids"
|
||||
done
|
||||
echo "[start-stack] PIDs salvati in $PID_DIR/asf-stack.pids"
|
||||
echo
|
||||
echo "Tipi 'Ctrl+C' per arrestare TUTTI i processi. Oppure usa: ./scripts/stop-stack.sh"
|
||||
echo
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 5) Smoke test (first 20s)
|
||||
# ------------------------------------------------------------
|
||||
deadline=$((SECONDS + 25))
|
||||
ok_core=0; ok_web=0
|
||||
while [ $SECONDS -lt $deadline ]; do
|
||||
if [ $CORE -eq 1 ] && [ $ok_core -eq 0 ]; then
|
||||
code=$(curl -s -m 4 -o /dev/null -w '%{http_code}' http://127.0.0.1:8000/api/v1/health || true)
|
||||
[ "$code" = "200" ] && { ok_core=1; echo " ✅ asf-core up /health HTTP=$code"; }
|
||||
fi
|
||||
if [ $WEB -eq 1 ] && [ $ok_web -eq 0 ]; then
|
||||
code=$(curl -s -m 4 -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/ || true)
|
||||
[ "$code" = "200" ] && { ok_web=1; echo " ✅ asf-web up / HTTP=$code"; }
|
||||
fi
|
||||
need=0
|
||||
[ $CORE -eq 1 ] && [ $ok_core -eq 0 ] && need=1
|
||||
[ $WEB -eq 1 ] && [ $ok_web -eq 0 ] && need=1
|
||||
[ $need -eq 0 ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ $CORE -eq 1 ] && [ $ok_core -eq 0 ] && echo " ⚠️ asf-core non ha risposto /health in tempo (guarda $LOG_DIR/asf-core.log)"
|
||||
[ $WEB -eq 1 ] && [ $ok_web -eq 0 ] && echo " ⚠️ asf-web non ha risposto / in tempo (Next.js 14 first compile slow: attendi / guarda $LOG_DIR/asf-web.log)"
|
||||
|
||||
echo
|
||||
echo "ASF stack ready. In attesa (foreground)… Ctrl+C = stop."
|
||||
|
||||
# wait
|
||||
for pid in "${pids[@]}"; do
|
||||
wait "$pid" || true
|
||||
done
|
||||
graceful_stop
|
||||
Reference in New Issue
Block a user