Files
html/api/scripts/fpm-saturation-guard.sh
opus 648f8242a9
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-21T12:39:36+02:00
2026-04-21 12:39:36 +02:00

74 lines
2.4 KiB
Bash
Executable File

#!/bin/bash
# V124 FPM Saturation Guard v2 - detection + alerte multi-pool (NO auto-restart)
# Doctrine 24: monitor saturation pattern V9.67 recurrent 11:00 UTC
# Aggregates all FPM pools (php7.4/8.4/8.5) for global pressure view
HISTORY=/tmp/fpm-saturation-history.json
MAX_HISTORY=288 # 24h at 5min interval
ALERT_THRESHOLD_PCT=85 # Alert if saturation >= 85%
# Get total max_children across all active pools
TOTAL_MAX=0
for conf in /etc/php/*/fpm/pool.d/*.conf; do
[ -f "$conf" ] || continue
v=$(grep -E "^pm.max_children" "$conf" 2>/dev/null | awk "{print \$NF}")
[ -n "$v" ] && TOTAL_MAX=$(( TOTAL_MAX + v ))
done
[ $TOTAL_MAX -eq 0 ] && TOTAL_MAX=150 # Fallback
# Get total active FPM workers (exclude master processes)
TOTAL_ACTIVE=$(ps -ef | grep "php-fpm: pool" | grep -v grep | wc -l)
# Get main pool (php8.5/www) state for detail
MAIN_MAX=$(grep -E "^pm.max_children" /etc/php/8.5/fpm/pool.d/www.conf 2>/dev/null | awk "{print \$NF}")
MAIN_MAX=${MAIN_MAX:-150}
MAIN_ACTIVE=$(ps -ef | grep "php-fpm: pool www$" | grep -v grep | wc -l)
CONNECTIONS=$(ss -ant 2>/dev/null | grep -c ":443")
LOAD1=$(cut -d" " -f1 /proc/loadavg)
TS=$(date +%s)
TSISO=$(date -Iseconds)
# Calculate saturation (main pool focus since it handles the principal traffic)
if [ $MAIN_MAX -gt 0 ]; then
SAT_PCT=$(( MAIN_ACTIVE * 100 / MAIN_MAX ))
else
SAT_PCT=0
fi
# Determine status
STATUS="healthy"
if [ $SAT_PCT -ge $ALERT_THRESHOLD_PCT ]; then
STATUS="SATURATED"
elif [ $SAT_PCT -ge 70 ]; then
STATUS="warn"
fi
# Output compact single line
echo "sat_pct=$SAT_PCT main=$MAIN_ACTIVE/$MAIN_MAX total=$TOTAL_ACTIVE/$TOTAL_MAX load1=$LOAD1 conn=$CONNECTIONS status=$STATUS ts=$TSISO"
# Append to history (keep last 288 entries = 24h)
ENTRY="{\"ts\":$TS,\"iso\":\"$TSISO\",\"sat_pct\":$SAT_PCT,\"main_active\":$MAIN_ACTIVE,\"main_max\":$MAIN_MAX,\"total_active\":$TOTAL_ACTIVE,\"total_max\":$TOTAL_MAX,\"load1\":$LOAD1,\"conn\":$CONNECTIONS,\"status\":\"$STATUS\"}"
if [ -f "$HISTORY" ]; then
python3 -c "
import json
try:
h = json.load(open('$HISTORY'))
if not isinstance(h, list): h = []
except: h = []
h.append($ENTRY)
h = h[-${MAX_HISTORY}:]
json.dump(h, open('$HISTORY', 'w'))
" 2>/dev/null
else
echo "[$ENTRY]" > "$HISTORY"
fi
# If SATURATED, log to syslog for trace
if [ "$STATUS" = "SATURATED" ]; then
logger -t "fpm-saturation-guard" "SATURATED sat_pct=$SAT_PCT main=$MAIN_ACTIVE/$MAIN_MAX load=$LOAD1"
fi
exit 0