#!/usr/bin/env bash # Idempotent starter for the X2 dashboard agent. # # Run this every minute from cron. If the agent is already up it does nothing; # if it is not, it starts it. That covers three cases with one mechanism: # * boot - the robot came back and nobody logged in # * crash - the process died # * manual kill - someone stopped it by hand # # Why not systemd? The agi account cannot enable linger (`loginctl # enable-linger` is denied, and sudo forbids running as root here), so a # `systemd --user` unit only runs while a login session exists - which is # exactly not the case after a power cycle. A cron watchdog needs no root and # does not depend on @reboot firing correctly. set -e DIR="$(dirname "$(readlink -f "$0")")" PORT="${X2_AGENT_PORT:-8781}" LOG="$DIR/agent.log" # Already listening? Nothing to do. Checking the port rather than the process # also catches a process that is alive but wedged before binding. if ss -ltn 2>/dev/null | grep -q ":${PORT} "; then exit 0 fi # Avoid stacking instances if a previous start is still coming up. if pgrep -f "x2_agent.py" >/dev/null 2>&1; then exit 0 fi echo "[$(date -Is)] agent not listening on ${PORT} - starting" >> "$LOG" # Keep the log from growing without bound (cron runs this every minute). if [ -f "$LOG" ] && [ "$(stat -c%s "$LOG" 2>/dev/null || echo 0)" -gt 1000000 ]; then tail -n 200 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG" fi setsid nohup "$DIR/run_agent.sh" >> "$LOG" 2>&1 < /dev/null & exit 0