Watchdog systemd + fix stabilité kiosk/backend
- Watchdog (30s) : vérifie backend, caméra, chromium, tue les orphelins, reboot auto après 10 échecs consécutifs (~5min sans service) - kiosk-session.sh : tue les backends orphelins au démarrage, trap EXIT pour cleanup quand le kiosk est tué - camera.py : force release USB avec timeout 2s quand connecter() échoue - main.py : uvicorn.run(app) au lieu de string pour éviter double import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
101
scripts/watchdog.sh
Normal file
101
scripts/watchdog.sh
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
# Watchdog photobooth — tourne toutes les 30s via systemd timer
|
||||
# Vérifie backend, camera, chromium. Escalade jusqu'au reboot si nécessaire.
|
||||
|
||||
HEALTH_URL="http://localhost/api/health"
|
||||
STATE_FILE="/tmp/photobooth-watchdog-failures"
|
||||
MAX_FAILURES=10 # 10 échecs × 30s = 5 min avant reboot
|
||||
LOG_TAG="photobooth-watchdog"
|
||||
|
||||
log() { logger -t "$LOG_TAG" "$1"; }
|
||||
|
||||
# Compteur d'échecs persistant
|
||||
failures=$(cat "$STATE_FILE" 2>/dev/null || echo 0)
|
||||
|
||||
# --- 1. Tuer les backends orphelins (ppid=1, pas rattachés au kiosk) ---
|
||||
while IFS= read -r line; do
|
||||
pid=$(echo "$line" | awk '{print $1}')
|
||||
ppid=$(echo "$line" | awk '{print $2}')
|
||||
if [ "$ppid" = "1" ]; then
|
||||
log "Backend orphelin détecté (pid=$pid), kill"
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
fi
|
||||
done < <(ps -eo pid,ppid,args | grep 'python.*backend.main' | grep -v grep)
|
||||
|
||||
# --- 2. Vérifier que le backend répond ---
|
||||
health=$(curl -sf --max-time 5 "$HEALTH_URL" 2>/dev/null)
|
||||
if [ -z "$health" ]; then
|
||||
log "Backend ne répond pas (échec $((failures+1))/$MAX_FAILURES)"
|
||||
# Vérifier si un process backend existe
|
||||
if ! pgrep -f 'python.*backend.main' > /dev/null 2>&1; then
|
||||
log "Aucun backend en cours — le kiosk devrait le relancer"
|
||||
fi
|
||||
failures=$((failures + 1))
|
||||
echo "$failures" > "$STATE_FILE"
|
||||
|
||||
if [ "$failures" -ge "$MAX_FAILURES" ]; then
|
||||
log "REBOOT: $MAX_FAILURES échecs consécutifs, redémarrage système"
|
||||
echo 0 > "$STATE_FILE"
|
||||
/usr/sbin/reboot
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Backend répond — extraire l'état caméra
|
||||
camera=$(echo "$health" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("camera",""))' 2>/dev/null)
|
||||
clients=$(echo "$health" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("clients",0))' 2>/dev/null)
|
||||
|
||||
# --- 3. Vérifier la caméra ---
|
||||
if [ "$camera" = "disconnected" ] || [ "$camera" = "erreur" ]; then
|
||||
log "Caméra déconnectée, tentative USB reset Canon"
|
||||
|
||||
# USB ioctl reset du Canon (vendor 04a9)
|
||||
python3 -c '
|
||||
import fcntl, glob, os
|
||||
for f in glob.glob("/sys/bus/usb/devices/*/idVendor"):
|
||||
if open(f).read().strip() == "04a9":
|
||||
d = os.path.dirname(f)
|
||||
bus = open(d + "/busnum").read().strip().zfill(3)
|
||||
dev = open(d + "/devnum").read().strip().zfill(3)
|
||||
path = f"/dev/bus/usb/{bus}/{dev}"
|
||||
with open(path, "wb") as fh:
|
||||
fcntl.ioctl(fh, 0x5514, 0)
|
||||
print(f"USB reset: {path}")
|
||||
' 2>/dev/null
|
||||
|
||||
# Si le Canon n'est même pas sur le bus USB
|
||||
if ! lsusb 2>/dev/null | grep -q "04a9"; then
|
||||
log "Canon absent du bus USB"
|
||||
failures=$((failures + 1))
|
||||
else
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
|
||||
echo "$failures" > "$STATE_FILE"
|
||||
|
||||
if [ "$failures" -ge "$MAX_FAILURES" ]; then
|
||||
log "REBOOT: caméra injoignable depuis $MAX_FAILURES cycles"
|
||||
echo 0 > "$STATE_FILE"
|
||||
/usr/sbin/reboot
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- 4. Vérifier Chromium ---
|
||||
if ! pgrep -f chromium > /dev/null 2>&1; then
|
||||
log "Chromium ne tourne pas — restart lightdm"
|
||||
systemctl restart lightdm
|
||||
failures=$((failures + 1))
|
||||
echo "$failures" > "$STATE_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- 5. Tuer gvfsd-gphoto2 s'il revient ---
|
||||
pkill -f gvfsd-gphoto2 2>/dev/null
|
||||
pkill -f gvfs-gphoto2-volume-monitor 2>/dev/null
|
||||
|
||||
# --- Tout va bien : reset compteur ---
|
||||
if [ "$failures" -gt 0 ]; then
|
||||
log "Système OK (camera=$camera, clients=$clients) — compteur remis à 0"
|
||||
fi
|
||||
echo 0 > "$STATE_FILE"
|
||||
Reference in New Issue
Block a user