🎉 Improved backend functionality & documentation, optimized database files, and introduced shutdown management 🧹

This commit is contained in:
2025-06-01 02:42:15 +02:00
parent ea12a470c9
commit 486647fade
10 changed files with 1052 additions and 407 deletions

View File

@@ -81,7 +81,7 @@ class PrinterQueueManager:
Verbesserte Version mit ordnungsgemäßem Thread-Management für Windows.
"""
def __init__(self):
def __init__(self, register_signal_handlers: bool = True):
self.is_running = False
self.monitor_thread = None
self.shutdown_event = threading.Event() # Sauberes Shutdown-Signal
@@ -89,65 +89,109 @@ class PrinterQueueManager:
self.last_status_cache = {} # Cache für letzten bekannten Status
self.notification_cooldown = {} # Verhindert Spam-Benachrichtigungen
self._lock = threading.Lock() # Thread-Sicherheit
self._signal_handlers_registered = False
# Windows-spezifische Signal-Handler registrieren
if os.name == 'nt':
# Signal-Handler nur registrieren wenn explizit gewünscht
# (Verhindert Interferenzen mit zentralem Shutdown-Manager)
if register_signal_handlers and os.name == 'nt':
self._register_signal_handlers()
def _register_signal_handlers(self):
"""Windows-spezifische Signal-Handler registrieren (nur wenn gewünscht)"""
if self._signal_handlers_registered:
return
try:
# Prüfe ob bereits zentrale Signal-Handler existieren
try:
from utils.shutdown_manager import is_shutdown_requested
if is_shutdown_requested is not None:
queue_logger.info("🔄 Zentrale Signal-Handler erkannt - deaktiviere lokale Handler")
return
except ImportError:
pass # Kein zentraler Manager verfügbar, verwende lokale Handler
signal.signal(signal.SIGINT, self._signal_handler)
signal.signal(signal.SIGTERM, self._signal_handler)
self._signal_handlers_registered = True
queue_logger.debug("✅ Lokale Signal-Handler für Queue Manager registriert")
except Exception as e:
queue_logger.warning(f"⚠️ Lokale Signal-Handler konnten nicht registriert werden: {e}")
def _signal_handler(self, signum, frame):
"""Signal-Handler für ordnungsgemäßes Shutdown."""
"""Signal-Handler für ordnungsgemäßes Shutdown (nur als Fallback)."""
queue_logger.warning(f"🛑 Signal {signum} empfangen - stoppe Queue Manager...")
self.stop()
def start(self):
"""Startet den Queue-Manager mit verbessertem Thread-Management."""
with self._lock:
if not self.is_running:
self.is_running = True
self.shutdown_event.clear()
self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=False)
self.monitor_thread.name = "PrinterQueueMonitor"
# Windows Thread-Manager verwenden falls verfügbar
if os.name == 'nt' and get_windows_thread_manager:
try:
thread_manager = get_windows_thread_manager()
thread_manager.register_thread(self.monitor_thread)
thread_manager.register_cleanup_function(self.stop)
queue_logger.debug("✅ Queue Manager bei Windows Thread-Manager registriert")
except Exception as e:
queue_logger.warning(f"⚠️ Windows Thread-Manager nicht verfügbar: {str(e)}")
self.monitor_thread.start()
queue_logger.info("✅ Printer Queue Manager erfolgreich gestartet")
def stop(self):
"""Stoppt den Queue-Manager ordnungsgemäß."""
"""Startet den Queue-Manager mit verbessertem Shutdown-Handling."""
with self._lock:
if self.is_running:
queue_logger.info("🔄 Beende Queue Manager...")
self.is_running = False
self.shutdown_event.set()
queue_logger.warning("Queue-Manager läuft bereits")
return self
queue_logger.info("🚀 Starte Printer Queue Manager...")
self.is_running = True
self.shutdown_event.clear()
# Monitor-Thread mit Daemon-Flag für automatische Beendigung
self.monitor_thread = threading.Thread(
target=self._monitor_loop,
name="PrinterQueueMonitor",
daemon=True # Automatische Beendigung bei Programm-Ende
)
self.monitor_thread.start()
queue_logger.info("✅ Printer Queue Manager gestartet")
return self
def stop(self):
"""Stoppt den Queue-Manager ordnungsgemäß mit verbessertem Timeout-Handling."""
with self._lock:
if not self.is_running:
queue_logger.debug("Queue-Manager ist bereits gestoppt")
return
if self.monitor_thread and self.monitor_thread.is_alive():
queue_logger.debug("⏳ Warte auf Thread-Beendigung...")
self.monitor_thread.join(timeout=10)
queue_logger.info("🔄 Beende Queue Manager...")
self.is_running = False
self.shutdown_event.set()
if self.monitor_thread and self.monitor_thread.is_alive():
queue_logger.debug("⏳ Warte auf Thread-Beendigung...")
# Verbessertes Timeout-Handling
try:
self.monitor_thread.join(timeout=5.0) # Reduziertes Timeout
if self.monitor_thread.is_alive():
queue_logger.warning("⚠️ Thread konnte nicht ordnungsgemäß beendet werden")
queue_logger.warning("⚠️ Thread konnte nicht in 5s beendet werden - setze als Daemon")
# Thread als Daemon markieren für automatische Beendigung
self.monitor_thread.daemon = True
else:
queue_logger.info("✅ Monitor-Thread erfolgreich beendet")
self.monitor_thread = None
queue_logger.info("Printer Queue Manager gestoppt")
except Exception as e:
queue_logger.error(f"Fehler beim Thread-Join: {e}")
self.monitor_thread = None
queue_logger.info("❌ Printer Queue Manager gestoppt")
def _monitor_loop(self):
"""Hauptschleife für die Überwachung der Drucker mit verbessertem Shutdown-Handling."""
queue_logger.info(f"🔄 Queue-Überwachung gestartet (Intervall: {self.check_interval} Sekunden)")
while self.is_running and not self.shutdown_event.is_set():
try:
# Prüfe auf zentrales Shutdown-Signal
try:
from utils.shutdown_manager import is_shutdown_requested
if is_shutdown_requested():
queue_logger.info("🛑 Zentrales Shutdown-Signal empfangen - beende Monitor-Loop")
break
except ImportError:
pass # Kein zentraler Manager verfügbar
self._check_waiting_jobs()
# Verwende Event.wait() statt time.sleep() für unterbrechbares Warten
@@ -379,10 +423,37 @@ def get_queue_manager() -> PrinterQueueManager:
return _queue_manager_instance
def start_queue_manager():
"""Startet den globalen Queue-Manager."""
manager = get_queue_manager()
manager.start()
return manager
"""Startet den globalen Queue-Manager sicher und ohne Signal-Handler-Interferenzen."""
global _queue_manager_instance
with _queue_manager_lock:
if _queue_manager_instance is not None:
queue_logger.warning("Queue-Manager läuft bereits")
return _queue_manager_instance
try:
queue_logger.info("🚀 Initialisiere neuen Queue-Manager...")
# Prüfe ob zentraler Shutdown-Manager verfügbar ist
register_signals = True
try:
from utils.shutdown_manager import is_shutdown_requested
if is_shutdown_requested is not None:
queue_logger.info("🔄 Zentrale Shutdown-Verwaltung erkannt - deaktiviere lokale Signal-Handler")
register_signals = False
except ImportError:
queue_logger.debug("Kein zentraler Shutdown-Manager verfügbar - verwende lokale Signal-Handler")
# Erstelle Queue-Manager ohne Signal-Handler wenn zentraler Manager vorhanden
_queue_manager_instance = PrinterQueueManager(register_signal_handlers=register_signals)
_queue_manager_instance.start()
queue_logger.info("✅ Queue-Manager erfolgreich gestartet")
return _queue_manager_instance
except Exception as e:
queue_logger.error(f"❌ Fehler beim Starten des Queue-Managers: {str(e)}")
_queue_manager_instance = None
raise
def stop_queue_manager():
"""Stoppt den globalen Queue-Manager definitiv und sicher."""