Files
photobooth/scripts/watchdog.sh
Jules 3c3dbd6c8b 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>
2026-06-27 13:21:02 +02:00

102 lines
3.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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"