69 lines
1.6 KiB
Bash
Executable File
69 lines
1.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Watchdog B MVP tri-state checker for OpenClaw main runtime.
|
|
# Output (stdout): exactly one token: running | stalled | idle
|
|
#
|
|
# Heuristic (MVP):
|
|
# - If openclaw.pid exists and process is alive => running unless logs are stale.
|
|
# - If process alive but log file hasn't changed for STALL_AFTER_SECONDS => stalled.
|
|
# - Otherwise => idle.
|
|
#
|
|
# Future extension point:
|
|
# - Replace/augment log-freshness with real main-agent session/ledger signals.
|
|
|
|
PID_FILE_DEFAULT="${OPENCLAW_PID_FILE:-/home/chchang/.openclaw/workspace/host-runtime/openclaw.pid}"
|
|
LOG_FILE_DEFAULT="${OPENCLAW_LOG_FILE:-/home/chchang/.openclaw/workspace/logs/openclaw.log}"
|
|
|
|
STALL_AFTER_SECONDS="${STALL_AFTER_SECONDS:-1200}" # 20 minutes default
|
|
NOW_EPOCH="$(date +%s)"
|
|
|
|
pid_file="$PID_FILE_DEFAULT"
|
|
log_file="$LOG_FILE_DEFAULT"
|
|
|
|
get_mtime_epoch() {
|
|
# GNU stat: %Y; BSD stat: -f %m
|
|
local path="$1"
|
|
if stat -c %Y "$path" >/dev/null 2>&1; then
|
|
stat -c %Y "$path"
|
|
else
|
|
stat -f %m "$path"
|
|
fi
|
|
}
|
|
|
|
proc_alive() {
|
|
local pid="$1"
|
|
[[ -n "$pid" ]] || return 1
|
|
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
|
|
kill -0 "$pid" >/dev/null 2>&1
|
|
}
|
|
|
|
# No pid file => idle
|
|
if [[ ! -f "$pid_file" ]]; then
|
|
echo "idle"
|
|
exit 0
|
|
fi
|
|
|
|
pid="$(tr -d ' \t\n\r' < "$pid_file" || true)"
|
|
|
|
# PID file exists but process not alive => idle
|
|
if ! proc_alive "$pid"; then
|
|
echo "idle"
|
|
exit 0
|
|
fi
|
|
|
|
# Process alive. If no log file, assume running (can't assess stall)
|
|
if [[ ! -f "$log_file" ]]; then
|
|
echo "running"
|
|
exit 0
|
|
fi
|
|
|
|
log_mtime="$(get_mtime_epoch "$log_file")"
|
|
age=$(( NOW_EPOCH - log_mtime ))
|
|
|
|
if (( age > STALL_AFTER_SECONDS )); then
|
|
echo "stalled"
|
|
else
|
|
echo "running"
|
|
fi
|