diff --git a/kill-maven.sh b/kill-maven.sh index f0754bd..725a3fa 100755 --- a/kill-maven.sh +++ b/kill-maven.sh @@ -1,8 +1,10 @@ #!/usr/bin/env bash # Unified script to stop all Maven services. # Usage: ./kill-maven.sh -# - Graceful SIGTERM is attempted first. -# - If any process lingers, force with SIGKILL. +# - Docker deploy: `docker compose stop` (see why below). +# - Bare-metal / dev run: graceful SIGTERM first, SIGKILL if anything lingers. +# Exits non-zero if it cannot confirm everything is stopped. It must never say +# "stopped" unless it checked. set -euo pipefail @@ -24,6 +26,69 @@ else LLM='llama-server.*\.gguf' fi +COMPOSE_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/docker-compose.yml" + +# --- containerised deploy ------------------------------------------------ +# docker-compose.yml does not set `pid: host`, so each container has its own +# PID namespace: pkill on the host sees nothing inside them. This script used +# to print "all stopped" while every daemon was still happily running. Stop the +# containers through compose instead — that actually reaches them. +# +# running_containers prints the ids of the project's running containers, or +# nothing. Empty output plus a non-zero return means "could not ask docker", +# which is different from "nothing is running" and is handled below. +running_containers() { + docker compose -f "$COMPOSE_FILE" ps -q --status running 2>/dev/null +} + +DOCKER_OK=0 +CONTAINERS="" +if command -v docker >/dev/null 2>&1 && [ -f "$COMPOSE_FILE" ]; then + if CONTAINERS="$(running_containers)"; then + DOCKER_OK=1 + fi +fi + +if [ "$DOCKER_OK" = 1 ] && [ -n "$CONTAINERS" ]; then + echo "--- Maven is running in containers: stopping via docker compose ---" + if ! docker compose -f "$COMPOSE_FILE" stop; then + echo "ERROR: 'docker compose stop' failed. Containers may still be running." >&2 + exit 1 + fi + echo "--- Verifying containers are gone ---" + LEFT="$(running_containers || true)" + if [ -n "$LEFT" ]; then + echo "ERROR: containers still running after stop:" >&2 + docker compose -f "$COMPOSE_FILE" ps >&2 || true + exit 1 + fi + echo "All containers stopped." + exit 0 +fi + +# --- bare-metal / dev run ----------------------------------------------- +# pgrep -f matches whole command lines, so a shell that merely mentions +# "mavend" (this script's own parent, for one) shows up. Drop ourselves and our +# parent, otherwise the SIGKILL sweep can take out the terminal you ran this in. +host_pids() { + pgrep -f "$PAT|$LLM" | grep -v -e "^$$\$" -e "^$PPID\$" | paste -sd, - || true +} +HOST_PIDS=$(host_pids) + +if [ -z "$HOST_PIDS" ]; then + # Nothing to kill on the host and no running containers. Either Maven is + # already down, or it is somewhere this script cannot see (another PID + # namespace, another user, docker unreachable). We cannot tell the + # difference, so refuse to claim success. + echo "ERROR: found no Maven processes on this host and no running containers." >&2 + if [ "$DOCKER_OK" != 1 ]; then + echo " Could not ask docker either — if this is the container deploy," >&2 + echo " run: docker compose -f $COMPOSE_FILE stop" >&2 + fi + echo " Nothing was stopped. Check by hand before assuming Maven is down." >&2 + exit 1 +fi + echo "--- Sending graceful SIGTERM to Maven services ---" pkill -TERM -f "$PAT" || true # mavend's Pdeathsig SIGKILLs its llama-server on exit, but sweep strays too @@ -32,12 +97,18 @@ pkill -TERM -f "$LLM" || true echo "--- Verifying processes are gone ---" sleep 1 -PIDS=$(pgrep -d ',' -f "$PAT|$LLM") || PIDS="" +PIDS=$(host_pids) if [ -n "$PIDS" ]; then echo "Warning: some processes still alive. PIDs: $PIDS" echo "--- Force killing with SIGKILL ---" echo "$PIDS" | tr ',' '\n' | xargs -r kill -9 + sleep 1 + LEFT=$(host_pids) + if [ -n "$LEFT" ]; then + echo "ERROR: still alive after SIGKILL. PIDs: $LEFT" >&2 + exit 1 + fi echo "Done (SIGKILL)." else echo "All services gracefully stopped." -fi \ No newline at end of file +fi