From 7090ec979fc27311ffec4514bbf81bcfc7372f3e Mon Sep 17 00:00:00 2001 From: busya Date: Mon, 29 Jun 2026 17:43:42 +0300 Subject: [PATCH] fix(run.sh): correct PID capture with process substitution, add SIGTERM trap, 3-phase cleanup Problem: pipeline cmd | awk & captured awks PID instead of Python PID. When cleanup killed AGENT_PID, awk died but Gradio kept port 7860 occupied. Fix: - Replace | awk & with > >(awk) 2>&1 & (process substitution) so 0 gives real PID - Trap SIGTERM + SIGHUP in addition to SIGINT - Three-phase cleanup: SIGTERM -> wait 1s -> SIGKILL -> fuser port fallback --- run.sh | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/run.sh b/run.sh index d8bcc074..20b2ffa6 100755 --- a/run.sh +++ b/run.sh @@ -186,21 +186,43 @@ setup_frontend cleanup() { echo "" echo "Stopping services..." + + # Phase 1: kill by tracked PID (process substitution ensures correct PID capture) if [ -n "$BACKEND_PID" ]; then - kill $BACKEND_PID 2>/dev/null || true + kill -TERM $BACKEND_PID 2>/dev/null || true fi if [ -n "$FRONTEND_PID" ]; then - kill $FRONTEND_PID 2>/dev/null || true + kill -TERM $FRONTEND_PID 2>/dev/null || true fi if [ -n "$AGENT_PID" ]; then - kill $AGENT_PID 2>/dev/null || true + kill -TERM $AGENT_PID 2>/dev/null || true fi + + # Phase 2: wait for graceful exit (up to 2s), then force kill + sleep 1 + if [ -n "$BACKEND_PID" ]; then + kill -KILL $BACKEND_PID 2>/dev/null || true + fi + if [ -n "$FRONTEND_PID" ]; then + kill -KILL $FRONTEND_PID 2>/dev/null || true + fi + if [ -n "$AGENT_PID" ]; then + kill -KILL $AGENT_PID 2>/dev/null || true + fi + + # Phase 3: fuser fallback — kill anything still on our ports (belt-and-suspenders) + if command -v fuser &>/dev/null; then + fuser -k ${AGENT_PORT}/tcp 2>/dev/null || true + fuser -k ${BACKEND_PORT}/tcp 2>/dev/null || true + fuser -k ${FRONTEND_PORT}/tcp 2>/dev/null || true + fi + echo "Services stopped." exit 0 } -# Trap SIGINT (Ctrl+C) -trap cleanup SIGINT +# Trap SIGINT (Ctrl+C), SIGTERM (kill), and SIGHUP (terminal close) +trap cleanup SIGINT SIGTERM SIGHUP # Start Backend start_backend() { @@ -234,8 +256,8 @@ start_backend() { fi local _color=$'\033[0;34m[Backend]\033[0m ' PYTHONUNBUFFERED=1 python3 -m uvicorn src.app:app --port "$BACKEND_PORT" \ - "${uvicorn_env_args[@]}" "${reload_args[@]}" 2>&1 | \ - awk -v prefix="$_color " '{print prefix $0; fflush()}' & + "${uvicorn_env_args[@]}" "${reload_args[@]}" \ + > >(awk -v prefix="$_color " '{print prefix $0; fflush()}') 2>&1 & BACKEND_PID=$! cd .. } @@ -247,8 +269,8 @@ start_frontend() { local _color=$'\033[0;32m[Frontend]\033[0m ' BACKEND_URL="http://127.0.0.1:${BACKEND_PORT}" \ GRADIO_URL="http://127.0.0.1:${AGENT_PORT}" \ - npm run dev -- --port "$FRONTEND_PORT" 2>&1 | \ - awk -v prefix="$_color " '{print prefix $0; fflush()}' & + npm run dev -- --port "$FRONTEND_PORT" \ + > >(awk -v prefix="$_color " '{print prefix $0; fflush()}') 2>&1 & FRONTEND_PID=$! cd .. } @@ -276,11 +298,11 @@ start_agent() { if [ "$DEV_MODE" = "true" ]; then echo -e "\033[0;35m[Agent]\033[0m Hot-reload enabled via watchfiles (watching src/agent/)" PYTHONUNBUFFERED=1 python3 -m watchfiles --filter python \ - "python -m src.agent.run" src/agent 2>&1 | \ - awk -v prefix="$_color " '{print prefix $0; fflush()}' & + "python -m src.agent.run" src/agent \ + > >(awk -v prefix="$_color " '{print prefix $0; fflush()}') 2>&1 & else - PYTHONUNBUFFERED=1 python3 -m src.agent.run 2>&1 | \ - awk -v prefix="$_color " '{print prefix $0; fflush()}' & + PYTHONUNBUFFERED=1 python3 -m src.agent.run \ + > >(awk -v prefix="$_color " '{print prefix $0; fflush()}') 2>&1 & fi AGENT_PID=$! cd ..