8.4 KiB
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
- Mehrfache Signal-Handler: Verschiedene Module registrierten eigene Signal-Handler, die sich gegenseitig interferiert haben
- Fehlende Koordination: Queue Manager, Scheduler und Datenbank-Cleanup wurden unkoordiniert beendet
- Keine Timeouts: Cleanup-Operationen konnten unbegrenzt lange dauern
- Scheduler-Shutdown-Probleme: Der Scheduler wurde nicht robust genug gestoppt
- 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
- Normales Shutdown:
Ctrl+C
oderSIGTERM
- Forciertes Shutdown: Mehrfache
Ctrl+C
- Timeout-Verhalten: Simuliere hängende Komponenten
- 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
- Import-Fehler: Shutdown-Manager nicht gefunden -> Fallback wird verwendet
- Timeout-Überschreitungen: Komponente reagiert nicht -> Wird übersprungen
- 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.