Fehlerhandling ausgearbeitet

This commit is contained in:
Tom 2026-10-28 10:19:27 +01:00
parent 0330c9fa1e
commit 7877faa786
2 changed files with 55 additions and 13 deletions

View file

@ -163,11 +163,25 @@ def main() -> None:
sys.exit(demo_workspace.run(settings, args.names, args.reset))
elif args.command == "web":
import uvicorn
# Start und Abbruch immer auf stderr, unabhängig von AIW_LOG_LEVEL: sonst endet ein Fehlstart still
print(f"aiw web: starte auf http://{args.host}:{args.port} (Log-Level {settings.log_level})", file=sys.stderr)
try:
# Logging wie oben eingerichtet; die Zugriffszeile schreibt die App selbst (mit Request-ID)
uvicorn.run("app.main:create_app", factory=True, host=args.host, port=args.port, reload=args.reload,
log_config=None, access_log=False)
except SystemExit as exit:
if exit.code:
print(f"aiw web: Start fehlgeschlagen (Exit-Code {exit.code}), z. B. Port {args.port} belegt oder "
"Fehler beim Laden der App. Details mit AIW_LOG_LEVEL=DEBUG.", file=sys.stderr)
raise
elif args.command == "worker":
port = settings.worker_http_port or "aus"
print(f"aiw worker: starte (Health-Port {port}, Log-Level {settings.log_level})", file=sys.stderr)
try:
run_worker(settings)
except Exception as error:
print(f"aiw worker: abgebrochen: {type(error).__name__}: {error}", file=sys.stderr)
raise
elif args.command == "create-admin":
create_admin_user(settings, args.username)
elif args.command in ("backup", "restore", "check"):

View file

@ -49,7 +49,20 @@ fail() { printf '\033[31m%s\033[0m\n' "$*" >&2; exit 1; }
# Zeilen eines Prozesses mit Namen versehen (portabel, auch mit der Bash von macOS)
prefix() { while IFS= read -r line; do printf '[%-6s] %s\n' "$1" "$line"; done; }
port_busy() { lsof -nP -iTCP:"$1" -sTCP:LISTEN >/dev/null 2>&1; }
# Lauscht etwas auf dem Port? Mit lsof, sonst (z. B. Linux ohne lsof) per Verbindungsversuch
port_busy() {
if command -v lsof >/dev/null 2>&1; then
lsof -nP -iTCP:"$1" -sTCP:LISTEN >/dev/null 2>&1
else
(exec 3<>"/dev/tcp/127.0.0.1/$1") 2>/dev/null
fi
}
# Wer belegt den Port? (für die Fehlermeldung; leer, wenn es sich nicht feststellen lässt)
port_owner() {
command -v lsof >/dev/null 2>&1 || return 0
lsof -nP -iTCP:"$1" -sTCP:LISTEN 2>/dev/null | awk 'NR == 2 { print $1 " (PID " $2 ")" }'
}
env_value() { grep -E "^$1=" .env 2>/dev/null | tail -1 | cut -d= -f2-; }
@ -108,7 +121,11 @@ fi
[ -f .env ] || fail "Keine .env. Ersteinrichtung mit: scripts/dev.sh --setup"
[ -n "${AIW_SECRET_KEY:-$(env_value AIW_SECRET_KEY)}" ] || fail "AIW_SECRET_KEY fehlt in .env (scripts/dev.sh --setup)."
port_busy "$PORT" && fail "Port $PORT ist belegt (läuft Bifröst schon?). Anderer Port: --port 8000"
port_busy "$PORT" && fail "Port $PORT ist belegt $(port_owner "$PORT") (läuft Bifröst schon?). Anderer Port: --port 8000"
WORKER_PORT=${AIW_WORKER_HTTP_PORT:-$(env_value AIW_WORKER_HTTP_PORT)}
WORKER_PORT=${WORKER_PORT:-9101}
port_busy "$WORKER_PORT" && fail "Port $WORKER_PORT (Health des Workers) ist belegt $(port_owner "$WORKER_PORT") \
– läuft noch ein Worker? Stoppen oder AIW_WORKER_HTTP_PORT in .env ändern."
say "PostgreSQL starten (127.0.0.1:55433)"
docker compose up -d --wait postgres
@ -126,7 +143,11 @@ export AIW_COOKIE_SECURE=${AIW_COOKIE_SECURE:-false}
export PYTHONUNBUFFERED=1
trap 'trap - INT TERM EXIT; echo; say "Stoppe Web, Worker und DB-Dienste"; kill 0 2>/dev/null; wait 2>/dev/null' INT TERM EXIT
# Gestartete Prozesse: PID, Name und Befehl zum Einzelstart (parallele Listen, Bash 3 von macOS kennt keine Maps)
PIDS=()
NAMES=()
COMMANDS=()
started() { PIDS+=("$1"); NAMES+=("$2"); COMMANDS+=("$3"); }
HINTS=()
@ -140,7 +161,8 @@ db_service() {
say "DB-Dienst $engine starten (Port $port)"
(cd services/db-mcp && DBMCP_API_KEYS="dev:$DEV_KEY" DBMCP_ALLOW_LOCAL=true DBMCP_PORT=$port \
DBMCP_BIND=127.0.0.1 "$ROOT/.venv/bin/python" -m "dbmcp.$engine" 2>&1 | prefix "$engine") &
PIDS+=($!)
started $! "DB-Dienst $engine (Port $port)" \
"cd services/db-mcp && DBMCP_API_KEYS=dev:$DEV_KEY DBMCP_ALLOW_LOCAL=true DBMCP_PORT=$port ../../.venv/bin/python -m dbmcp.$engine"
for _ in $(seq 50); do curl -sf "http://127.0.0.1:$port/ready" >/dev/null 2>&1 && break; sleep 0.2; done
fi
HINTS+=("$engine: URL http://localhost:$port/mcp Schlüssel des Dienstes $DEV_KEY")
@ -160,10 +182,10 @@ fi
say "Web starten: http://127.0.0.1:$PORT"
(uv run aiw web --port "$PORT" 2>&1 | prefix web) &
PIDS+=($!)
started $! "Web (Port $PORT)" "uv run aiw web --port $PORT"
say "Worker starten"
(uv run aiw worker 2>&1 | prefix worker) &
PIDS+=($!)
started $! "Worker" "uv run aiw worker"
if $RESET; then
say "Fertig von null. Noch offen: als admin ein Modell einrichten (Administration → Modelle und Zugänge)."
@ -174,11 +196,17 @@ else
fi
for hint in "${HINTS[@]}"; do echo " $hint"; done
# Endet ein Prozess (z. B. Fehler beim Start), alles stoppen
# Endet ein Prozess (z. B. Fehler beim Start), sagen welcher und alles stoppen
while true; do
for pid in "${PIDS[@]}"; do
if ! kill -0 "$pid" 2>/dev/null; then
fail "Ein Prozess hat sich beendet (siehe Log oben)."
for i in "${!PIDS[@]}"; do
if ! kill -0 "${PIDS[$i]}" 2>/dev/null; then
code=0
wait "${PIDS[$i]}" 2>/dev/null || code=$?
echo
printf '\033[31m%s hat sich beendet (Exit-Code %s).\033[0m\n' "${NAMES[$i]}" "$code" >&2
echo "Seine Ausgabe steht oben mit Präfix; fehlt sie, den Prozess einzeln starten und die Meldung ansehen:" >&2
echo " ${COMMANDS[$i]}" >&2
exit 1
fi
done
sleep 1