#!/bin/sh # entrypoint.sh — runs the Python monitoring loop and a static HTTP server # side by side in a single container. POSIX sh so it works on Alpine's # default shell. set -eu PORT="${PORT:-8080}" WEB_DIR="${WEB_DIR:-/app/web}" echo "[entrypoint] starting monitor loop" python3 /app/monitor.py & MONITOR_PID=$! echo "[entrypoint] serving dashboard from ${WEB_DIR} on 0.0.0.0:${PORT}" cd "${WEB_DIR}" python3 -m http.server "${PORT}" --bind 0.0.0.0 & SERVER_PID=$! # Forward termination signals to both children and wait for them so the # container shuts down cleanly (e.g. on `docker stop` / platform redeploys). term_handler() { echo "[entrypoint] shutting down..." kill -TERM "$MONITOR_PID" "$SERVER_PID" 2>/dev/null || true wait "$MONITOR_PID" "$SERVER_PID" 2>/dev/null || true exit 0 } trap term_handler TERM INT # busybox ash (Alpine's /bin/sh) has no `wait -n`, so poll instead: if # either child dies unexpectedly, bring the whole container down so the # orchestrator (Docker/Kubernetes/Cloud Run/etc.) can restart it. while true; do if ! kill -0 "$MONITOR_PID" 2>/dev/null; then echo "[entrypoint] monitor loop exited unexpectedly — stopping container" term_handler fi if ! kill -0 "$SERVER_PID" 2>/dev/null; then echo "[entrypoint] http server exited unexpectedly — stopping container" term_handler fi sleep 2 done