Projektarbeit-MYP/backend/docs/SHUTDOWN_VERBESSERUNGEN.md

8.4 KiB

Shutdown- und Cleanup-Verbesserungen

Übersicht

Die Anwendung hatte Probleme beim ordnungsgemäßen Herunterfahren und Cleanup, die zu hängenden Prozessen und inkonsistenten Zuständen führten. Diese Dokumentation beschreibt die implementierten Verbesserungen.

Identifizierte Probleme

Vorherige Probleme

  1. Mehrfache Signal-Handler: Verschiedene Module registrierten eigene Signal-Handler, die sich gegenseitig interferiert haben
  2. Fehlende Koordination: Queue Manager, Scheduler und Datenbank-Cleanup wurden unkoordiniert beendet
  3. Keine Timeouts: Cleanup-Operationen konnten unbegrenzt lange dauern
  4. Scheduler-Shutdown-Probleme: Der Scheduler wurde nicht robust genug gestoppt
  5. Komplexe Datenbank-Operationen: Riskante WAL-Mode-Switches während des Shutdowns

Symptome in den Logs

🛑 Signal 2 empfangen - fahre System herunter...
⚠️ Thread konnte nicht ordnungsgemäß beendet werden
❌ Fehler beim Stoppen des Schedulers
🔄 Führe robustes Datenbank-Cleanup durch...

Implementierte Lösung: Zentraler Shutdown-Manager

Neue Architektur

1. Zentraler Shutdown-Manager (utils/shutdown_manager.py)

class ShutdownManager:
    """
    Koordiniert alle Cleanup-Operationen mit Timeouts und Prioritäten
    """

Hauptfunktionen:

  • Koordinierte Beendigung: Alle Komponenten werden in der richtigen Reihenfolge gestoppt
  • Prioritäts-basiertes Cleanup: Cleanup-Funktionen werden nach Priorität (1=hoch, 3=niedrig) ausgeführt
  • Timeout-Management: Jede Operation hat ein konfigurierbares Timeout
  • Fehlerbehandlung: Einzelne Fehler stoppen nicht den gesamten Shutdown-Prozess
  • Plattform-spezifisch: Unterstützt Windows und Unix/Linux Signal-Handling

2. Komponenten-Registrierung

# Queue Manager registrieren
shutdown_manager.register_queue_manager(queue_module)

# Scheduler registrieren  
shutdown_manager.register_scheduler(scheduler, SCHEDULER_ENABLED)

# Datenbank-Cleanup registrieren
shutdown_manager.register_database_cleanup()

# Windows Thread Manager registrieren
shutdown_manager.register_windows_thread_manager()

3. Prioritäten-System

  • Priorität 1 (Hoch): Queue Manager, Scheduler - werden zuerst gestoppt
  • Priorität 2 (Mittel): Windows Thread Manager - wird in der Mitte gestoppt
  • Priorität 3 (Niedrig): Datenbank-Cleanup - wird am Ende ausgeführt

Verbesserungen im Detail

Queue Manager (utils/queue_manager.py)

Vorher:

  • Registrierte eigene Signal-Handler, die interferierten
  • Feste 10-Sekunden-Timeouts ohne Flexibilität
  • Thread-Join ohne Fallback-Strategien

Nachher:

def __init__(self, register_signal_handlers: bool = True):
    # Signal-Handler nur wenn explizit gewünscht
    if register_signal_handlers and os.name == 'nt':
        self._register_signal_handlers()

Verbesserungen:

  • Optionale Signal-Handler-Registrierung
  • Prüfung auf zentralen Shutdown-Manager
  • Reduzierte Timeouts (5 Sekunden)
  • Daemon-Thread-Fallback für automatische Beendigung
  • Verbesserte Fehlerbehandlung

Scheduler-Integration

Vorher:

scheduler.stop()  # Einfache Stop-Methode

Nachher:

def stop_scheduler():
    if hasattr(scheduler, 'shutdown'):
        scheduler.shutdown(wait=True)  # Robustere Methode
    elif hasattr(scheduler, 'stop'):
        scheduler.stop()

Datenbank-Cleanup

Vorher:

  • Riskante WAL-Mode-Switches während Shutdown
  • Komplexe Operationen ohne Timeout

Nachher:

def safe_database_cleanup():
    # Kein riskantes Mode-Switching beim Shutdown
    result = safe_database_cleanup(force_mode_switch=False)
    
    # Fallback auf einfaches WAL-Checkpoint
    result = conn.execute(text("PRAGMA wal_checkpoint(PASSIVE)"))

Konfiguration und Verwendung

Startup-Konfiguration in app.py

# Initialisiere zentralen Shutdown-Manager
from utils.shutdown_manager import get_shutdown_manager
shutdown_manager = get_shutdown_manager(timeout=45)

# Registriere alle Komponenten
shutdown_manager.register_queue_manager(queue_module)
shutdown_manager.register_scheduler(scheduler, SCHEDULER_ENABLED)
shutdown_manager.register_database_cleanup()
shutdown_manager.register_windows_thread_manager()

Fallback-Mechanismus

Falls der Shutdown-Manager nicht verfügbar ist, wird ein Fallback-Signal-Handler verwendet:

except ImportError as e:
    # Fallback auf vereinfachte Signal-Handler
    def fallback_signal_handler(sig, frame):
        stop_queue_manager()
        if scheduler:
            scheduler.shutdown(wait=True)
        sys.exit(0)

Timeout-Konfiguration

Komponente Timeout Begründung
Queue Manager 15s Zeit für Thread-Beendigung und Cleanup
Scheduler 10s Zeit für laufende Jobs zu beenden
Datenbank-Cleanup 20s Zeit für WAL-Checkpoint und Optimierung
Windows Thread Manager 15s Zeit für alle verwalteten Threads
Gesamt 45s Maximum für komplettes Shutdown

Signal-Handler-Koordination

Vorher (Problematisch)

app.py          -> SIGINT, SIGTERM, SIGBREAK
queue_manager.py -> SIGINT, SIGTERM  
windows_fixes.py -> SIGINT, SIGTERM, SIGBREAK

Problem: Mehrfache Handler interferieren, inkonsistente Cleanup-Reihenfolge

Nachher (Koordiniert)

shutdown_manager.py -> SIGINT, SIGTERM, SIGBREAK (zentral)
queue_manager.py    -> Keine Handler (oder optional als Fallback)
windows_fixes.py    -> Registriert beim Shutdown-Manager

Monitoring und Debugging

Detaillierte Logs

🔧 Shutdown-Manager initialisiert
✅ Queue Manager beim Shutdown-Manager registriert  
🔄 Starte koordiniertes System-Shutdown...
🔄 Stoppe 1 registrierte Komponenten...
🧹 Führe 4 Cleanup-Funktionen aus...
✅ Koordiniertes Shutdown abgeschlossen in 3.2s
🏁 System wird beendet...

Timeout-Überwachung

✅ Queue Manager abgeschlossen in 2.1s
⏱️ Datenbank Cleanup Timeout nach 20.0s
❌ Fehler bei Cleanup 'Windows Thread Manager': Connection refused

Fehlerbehandlung

Robuste Cleanup-Ausführung

  • Einzelfehler stoppen nicht das gesamte Shutdown
  • Timeouts verhindern hängende Operationen
  • Fallback-Strategien für kritische Komponenten
  • Detaillierte Fehler-Logs für Debugging

Graceful Degradation

try:
    # Versuche optimalen Cleanup
    safe_database_cleanup()
except Exception:
    # Fallback auf minimalen Cleanup
    basic_wal_checkpoint()

Testen der Verbesserungen

Test-Szenarien

  1. Normales Shutdown: Ctrl+C oder SIGTERM
  2. Forciertes Shutdown: Mehrfache Ctrl+C
  3. Timeout-Verhalten: Simuliere hängende Komponenten
  4. Komponenten-Ausfälle: Simuliere Fehler in einzelnen Cleanup-Funktionen

Erwartete Verbesserungen

  • Reduzierte Shutdown-Zeit: Von >30s auf <10s in normalen Fällen
  • Konsistente Logs: Klare Shutdown-Sequenz sichtbar
  • Keine hängenden Prozesse: Alle Threads werden ordnungsgemäß beendet
  • Robuste Datenbank: Keine WAL-Korruption oder Lock-Probleme

Wartung und Erweiterung

Neue Komponenten hinzufügen

# Für Komponenten mit stop()-Methode
shutdown_manager.register_component("Meine Komponente", component, "stop")

# Für Cleanup-Funktionen
shutdown_manager.register_cleanup_function(
    func=my_cleanup_function,
    name="Meine Cleanup-Funktion", 
    priority=2,
    timeout=15
)

Troubleshooting

Häufige Probleme

  1. Import-Fehler: Shutdown-Manager nicht gefunden -> Fallback wird verwendet
  2. Timeout-Überschreitungen: Komponente reagiert nicht -> Wird übersprungen
  3. Signal-Handler-Konflikte: Alte Handler noch registriert -> Deregistrierung nötig

Debug-Logs aktivieren

shutdown_logger.setLevel(logging.DEBUG)

Zukünftige Verbesserungen

  • Health-Checks: Überwachung der Komponenten-Zustände
  • Konfigurierbares Verhalten: Externe Konfiguration für Timeouts und Prioritäten
  • Metrics: Sammlung von Shutdown-Performance-Daten
  • Web-Interface: Admin-Interface für Shutdown-Management

Fazit

Die Shutdown-Verbesserungen lösen die ursprünglichen Probleme durch:

  • Zentrale Koordination aller Cleanup-Operationen
  • Timeout-basierte Fehlerbehandlung
  • Prioritäts-gesteuerte Ausführungsreihenfolge
  • Robuste Fallback-Mechanismen

Das Ergebnis ist ein zuverlässiges, schnelles und debugbares Shutdown-Verhalten.