← back to Cncp Mcp
scripts/audit-pm2-caps.sh
69 lines
#!/usr/bin/env bash
# audit-pm2-caps.sh — read-only audit of pm2 procs missing memory/CPU caps.
#
# Soft-caps are Steve's protection against a single leaking pm2 proc dragging
# load to 500+. Each process SHOULD have `max_memory_restart` set in its
# ecosystem.config.{js,cjs}. This script finds the gaps and prints a punch list.
#
# Usage:
# bash ~/Projects/cncp-mcp/scripts/audit-pm2-caps.sh
#
# Output: one line per cap-less proc with the candidate ecosystem file path.
set -u
PM2_BIN="${PM2_BIN:-$HOME/.npm-global/bin/pm2}"
[[ -x "$PM2_BIN" ]] || PM2_BIN="$(/usr/bin/which pm2 2>/dev/null || echo pm2)"
"$PM2_BIN" jlist 2>/dev/null > /tmp/audit-pm2-caps.json
/usr/bin/python3 <<'PY'
import json, os
try:
procs = json.load(open('/tmp/audit-pm2-caps.json'))
except Exception as e:
print(f"pm2 jlist parse failed: {e}")
raise SystemExit(1)
uncapped = []
capped = []
for p in procs:
env = p.get('pm2_env', {})
name = p.get('name', '?')
max_mem = env.get('max_memory_restart')
pm_exec_path = env.get('pm_exec_path', '')
pm_cwd = env.get('pm_cwd', '')
# Find candidate ecosystem file
eco = None
for candidate in ('ecosystem.config.js', 'ecosystem.config.cjs'):
path = os.path.join(pm_cwd, candidate) if pm_cwd else ''
if path and os.path.isfile(path):
eco = path
break
row = (name, max_mem, eco or '(no ecosystem.config.{js,cjs} found)')
if max_mem:
capped.append(row)
else:
uncapped.append(row)
print(f"=== capped procs: {len(capped)} ===")
for n, m, e in capped[:10]:
print(f" ✓ {n:<32} max_memory_restart={m}")
if len(capped) > 10:
print(f" ... and {len(capped)-10} more")
print()
print(f"=== UNCAPPED procs (no max_memory_restart): {len(uncapped)} ===")
for n, m, e in uncapped:
print(f" ✗ {n:<32} → {e}")
print()
print("Fix pattern in each ecosystem.config.{js,cjs}:")
print(" module.exports = { apps: [{ name: '...', script: '...',")
print(" max_memory_restart: '500M', // sister-sites: try 300M; LLM agents: 1G")
print(" cron_restart: '0 4 * * *', // optional nightly bounce at 4am")
print(" }] };")
print()
print("After editing each ecosystem file:")
print(" pm2 reload <name> --update-env")
PY