diff --git a/api/Dockerfile b/api/Dockerfile index 6e8831a..bcda1a6 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -85,7 +85,7 @@ ENV PYTHONUNBUFFERED=1 # Copy application code COPY ./api ./api -COPY ./scripts/start_services_dev.sh ./scripts/start_services_dev.sh +COPY ./scripts/start_services_docker.sh ./scripts/start_services_docker.sh # ts_validator Node deps (built in ts-deps stage with full node:22-slim image). # The validator runs as a short-lived subprocess from api/mcp_server/ts_bridge.py. @@ -104,4 +104,4 @@ ENV LOG_TO_FILE=false EXPOSE 8000 # Run the FastAPI app with uvicorn -CMD ["./scripts/start_services_dev.sh"] \ No newline at end of file +CMD ["./scripts/start_services_docker.sh"] \ No newline at end of file diff --git a/docs/contribution/setup.mdx b/docs/contribution/setup.mdx index 6dc95d0..a2629ab 100644 --- a/docs/contribution/setup.mdx +++ b/docs/contribution/setup.mdx @@ -109,6 +109,21 @@ tail -f logs/latest/*.log Get-Content logs/latest/*.log -Wait ``` + +#### Restarting the backend +Re-run the same start script to restart. It reads the PID files under `run/`, terminates the previous services along with their descendants, and starts fresh ones. + +```bash macOS/Linux +bash scripts/start_services_dev.sh +``` +```powershell Windows +.\scripts\start_services_dev.ps1 +``` + + + +`uvicorn` runs with `--reload --reload-dir api`, so edits under `api/` are picked up automatically — no restart needed. The other services (`ari_manager`, `campaign_orchestrator`, `arq`) do **not** auto-reload; re-run the start script after changing code they execute. + 10. Start the UI ``` cd ui && npm run dev diff --git a/scripts/start_services_dev.ps1 b/scripts/start_services_dev.ps1 index a9470c4..47e74b6 100644 --- a/scripts/start_services_dev.ps1 +++ b/scripts/start_services_dev.ps1 @@ -1,13 +1,12 @@ #!/usr/bin/env pwsh # Start Dograh services in development mode (Windows) -# Usage: .\scripts\start_services_dev.ps1 [-ArqWorkers 2] [-NoMigrations] [-IncludeTelephonyWorkers] +# Usage: .\scripts\start_services_dev.ps1 [-NoMigrations] [-IncludeTelephonyWorkers] # # Note: Telephony workers (ari_manager, campaign_orchestrator) are disabled by # default on Windows because they use Unix signal handlers not supported by the # Windows asyncio event loop. Param( - [int]$ArqWorkers = 1, [switch]$NoMigrations, [switch]$IncludeTelephonyWorkers ) @@ -61,10 +60,7 @@ if ($IncludeTelephonyWorkers) { } $serviceSpecs += @{ Name = 'uvicorn'; Cmd = "uvicorn api.app:app --host 0.0.0.0 --port $($env:UVICORN_BASE_PORT) --reload --reload-dir api" } - -for ($i = 1; $i -le $ArqWorkers; $i++) { - $serviceSpecs += @{ Name = "arq$i"; Cmd = "python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG" } -} +$serviceSpecs += @{ Name = 'arq'; Cmd = "python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG" } ############################################################################### ### 3) Activate virtual environment diff --git a/scripts/start_services_dev.sh b/scripts/start_services_dev.sh index 91fdf73..23458aa 100755 --- a/scripts/start_services_dev.sh +++ b/scripts/start_services_dev.sh @@ -17,7 +17,6 @@ LOG_DIR="$BASE_LOG_DIR/$TIMESTAMP" # Timestamped log directory LATEST_LINK="$BASE_LOG_DIR/latest" # Symlink to latest logs VENV_PATH="$BASE_DIR/venv" -ARQ_WORKERS=${ARQ_WORKERS:-1} LOG_TO_FILE=${LOG_TO_FILE:-true} cd "$BASE_DIR" @@ -42,20 +41,16 @@ SERVICE_NAMES=( "ari_manager" "campaign_orchestrator" "uvicorn" + "arq" ) SERVICE_COMMANDS=( "python -m api.services.telephony.ari_manager" "python -m api.services.campaign.campaign_orchestrator" "uvicorn api.app:app --host 0.0.0.0 --port $UVICORN_BASE_PORT --reload --reload-dir api" + "python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG" ) -# Add ARQ workers dynamically -for ((i=1; i<=ARQ_WORKERS; i++)); do - SERVICE_NAMES+=("arq$i") - SERVICE_COMMANDS+=("python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG") -done - ############################################################################### ### 3) Activate virtual environment ############################################################################### @@ -217,6 +212,3 @@ echo "Logs: tail -f $LOG_DIR/*.log" echo "Rotated logs: ls $LOG_DIR/*.log.*" echo "To stop: ./scripts/stop_services.sh" echo "──────────────────────────────────────────────────" - -# Keep the script alive (required for Docker - PID 1 must not exit) -wait diff --git a/scripts/start_services_docker.sh b/scripts/start_services_docker.sh new file mode 100755 index 0000000..48965c9 --- /dev/null +++ b/scripts/start_services_docker.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -e + +############################################################################### +### CONFIGURATION +############################################################################### + +BASE_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)" +ENV_FILE="$BASE_DIR/api/.env" + +ARQ_WORKERS=${ARQ_WORKERS:-1} +FASTAPI_WORKERS=${FASTAPI_WORKERS:-1} +UVICORN_BASE_PORT=${UVICORN_BASE_PORT:-8000} + +cd "$BASE_DIR" +echo "Starting Dograh Services (DOCKER) at $(date) in BASE_DIR: ${BASE_DIR}" + +############################################################################### +### 1) Load env file if mounted (env normally comes from docker-compose) +############################################################################### + +if [[ -f "$ENV_FILE" ]]; then + set -a && . "$ENV_FILE" && set +a +fi + +############################################################################### +### 2) Run migrations +############################################################################### + +alembic -c "$BASE_DIR/api/alembic.ini" upgrade head + +############################################################################### +### 3) Signal handling — forward TERM/INT to children for clean docker stop +############################################################################### + +pids=() + +shutdown() { + echo "Received shutdown signal, stopping services..." + for pid in "${pids[@]}"; do + kill -TERM "$pid" 2>/dev/null || true + done + wait + exit 0 +} + +trap shutdown TERM INT + +start() { + local name=$1 + shift + echo "→ Starting $name" + "$@" & + pids+=($!) + echo " $name PID $!" +} + +############################################################################### +### 4) Start services (logs go to stdout for `docker logs`) +############################################################################### + +start ari_manager python -m api.services.telephony.ari_manager +start campaign_orchestrator python -m api.services.campaign.campaign_orchestrator +start uvicorn uvicorn api.app:app --host 0.0.0.0 --port "$UVICORN_BASE_PORT" --workers "$FASTAPI_WORKERS" + +for ((i=1; i<=ARQ_WORKERS; i++)); do + start "arq$i" python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG +done + +############################################################################### +### 5) Wait — if any service exits, tear the container down so docker restarts +############################################################################### + +wait -n +echo "A service exited; tearing down container." +shutdown