3.5 KiB
3.5 KiB
Multi-Server Resource Threshold Alerting
Monitors RAM, disk, and CPU usage across all VPS servers, alerting via Telegram when thresholds are crossed. Runs as a Hermes no-agent cron job every 15 minutes.
Architecture
Bash script (vps-threshold-check.sh)
└─ Server manifest (hostname|ip|local_flag)
├─ ssh to each remote server (itpp-infra key, 5s timeout)
└─ local commands for core server
├─ Collect: df -h / (disk %), free (RAM %), top -bn1 (CPU %), nproc
├─ Check 3 thresholds (80%, 90%, 95%) per metric per server
├─ 24h re-alert suppression via JSON state file
└─ stdout on alert → no-agent cron → Telegram delivery
Script: /root/.hermes/scripts/vps-threshold-check.sh
Server Manifest Format
"hostname|ip_address|is_local_flag"
is_local_flag=1— run commands directly (core server)is_local_flag=0— SSH via/root/.ssh/itpp-infrakey
Alert State File
/root/.hermes/data/threshold-alerts.json — JSON object keyed by hostname_metric_threshold (e.g. ai_disk_90), value is ISO timestamp of last alert.
Threshold Logic
- Per threshold: 80%, 90%, and 95% — each tracked independently
- Alert on first crossing: records timestamp, outputs alert to stdout
- Suppress re-alerts: 86,400 seconds (24h) cooldown per key
- Reset on drop: when metric falls below a threshold, that alert key is removed from state — so it can re-alert immediately on the next spike
- No output when healthy: silent stdout = no Telegram noise (cron skips delivery)
Cron Job
Name: vps-threshold-check
Schedule: every 15m
Script: vps-threshold-check.sh
Mode: no-agent (script stdout delivered directly)
Deliver: telegram
Uses Hermes' no-agent cron pattern: script writes alert text to stdout → cron scheduler delivers to Telegram via the running gateway's TELEGRAM_BOT_TOKEN env var.
Threshold Design Decisions
- 3-tier thresholds rather than a single number: gives escalating urgency (80% ≈ warning, 90% ≈ critical, 95% ≈ emergency)
- Per-threshold tracking not per-metric: if disk jumps from 70% to 92%, both the 80% and 90% alerts fire once (not every 15 min)
- 24h re-alert window prevents notification fatigue but ensures admins still hear about sustained issues
- keyed suppression rather than last-N-hours per server: handles the case where a metric oscillates across a threshold
Known Pitfalls
- CPU measurement:
top -bn1reads the first sample which may show 0% on idle systems. For accurate CPU under load, usetop -bn2 | awk '/Cpu\(s\)/ {print $2}' | tail -1(second sample picks up between-snapshot delta). The current script uses the first sample which is fine for sustained high-CPU scenarios. - SSH timeouts: each server has a 5s ConnectTimeout. If a server is unreachable, the
sshoutput is empty and metrics default to 0 — no false alarms. - Alert state persistence: if the JSON file is deleted, all thresholds re-alert on the next run (resets the 24h clock). This is intentional — better to re-alert than stay silent.
- Telegram env vars: delivery requires the gateway process to have
TELEGRAM_BOT_TOKEN,TELEGRAM_ALLOWED_USERS, andTELEGRAM_HOME_CHANNELin its environment (set athermes gateway runlaunch). These are inherited from the parent shell or.env. - Gateway not running: if the gateway is down, the cron scheduler logs failed delivery but the script still runs fine — the JSON state file is updated regardless.