🎉 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

@ -6537,86 +6537,50 @@ if __name__ == "__main__":
os.environ['FLASK_ENV'] = 'development'
os.environ['PYTHONIOENCODING'] = 'utf-8'
os.environ['PYTHONUTF8'] = '1'
# Windows-spezifisches Signal-Handling für ordnungsgemäßes Shutdown
def signal_handler(sig, frame):
"""Signal-Handler für ordnungsgemäßes Shutdown."""
app_logger.warning(f"🛑 Signal {sig} empfangen - fahre System herunter...")
try:
# Queue Manager stoppen
app_logger.info("🔄 Beende Queue Manager...")
stop_queue_manager()
# Scheduler stoppen falls aktiviert
if SCHEDULER_ENABLED and scheduler:
try:
scheduler.stop()
app_logger.info("Job-Scheduler gestoppt")
except Exception as e:
app_logger.error(f"Fehler beim Stoppen des Schedulers: {str(e)}")
# ===== ROBUSTES DATENBANK-CLEANUP MIT NEUER LOGIC =====
app_logger.info("💾 Führe robustes Datenbank-Cleanup durch...")
try:
# Importiere und verwende den neuen DatabaseCleanupManager
from utils.database_cleanup import safe_database_cleanup
# Führe umfassendes, sicheres Cleanup durch
cleanup_result = safe_database_cleanup(force_mode_switch=True)
if cleanup_result["success"]:
app_logger.info(f"✅ Datenbank-Cleanup erfolgreich: {', '.join(cleanup_result['operations'])}")
if cleanup_result.get("wal_files_removed", False):
app_logger.info("✅ WAL- und SHM-Dateien erfolgreich entfernt")
else:
app_logger.warning(f"⚠️ Datenbank-Cleanup mit Problemen: {', '.join(cleanup_result['errors'])}")
# Trotzdem weiter - wenigstens WAL-Checkpoint versucht
except ImportError:
# Fallback auf die alte Methode falls Cleanup-Manager nicht verfügbar
app_logger.warning("Fallback: Verwende Legacy-Datenbank-Cleanup...")
try:
from models import create_optimized_engine
from sqlalchemy import text
engine = create_optimized_engine()
with engine.connect() as conn:
# Nur WAL-Checkpoint - kein risikoreicher Mode-Switch
app_logger.info("📝 Führe WAL-Checkpoint durch...")
result = conn.execute(text("PRAGMA wal_checkpoint(TRUNCATE)")).fetchone()
if result:
app_logger.info(f"WAL-Checkpoint abgeschlossen: {result[1]} Seiten übertragen, {result[2]} Seiten zurückgesetzt")
conn.commit()
# Engine-Connection-Pool schließen
engine.dispose()
app_logger.info("✅ Legacy-Datenbank-Cleanup abgeschlossen")
except Exception as db_error:
app_logger.error(f"❌ Fehler beim Legacy-Datenbank-Cleanup: {str(db_error)}")
except Exception as cleanup_error:
app_logger.error(f"❌ Fehler beim robusten Datenbank-Cleanup: {str(cleanup_error)}")
app_logger.info("✅ Shutdown abgeschlossen")
sys.exit(0)
except Exception as e:
app_logger.error(f"❌ Fehler beim Shutdown: {str(e)}")
sys.exit(1)
# Signal-Handler registrieren (Windows-kompatibel)
if os.name == 'nt': # Windows
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Zusätzlich für Flask-Development-Server
signal.signal(signal.SIGBREAK, signal_handler)
else: # Unix/Linux
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGHUP, signal_handler)
# ===== INITIALISIERE ZENTRALEN SHUTDOWN-MANAGER =====
try:
from utils.shutdown_manager import get_shutdown_manager
shutdown_manager = get_shutdown_manager(timeout=45) # 45 Sekunden Gesamt-Timeout
app_logger.info("✅ Zentraler Shutdown-Manager initialisiert")
except ImportError as e:
app_logger.error(f"❌ Shutdown-Manager konnte nicht geladen werden: {e}")
# Fallback auf die alte Methode
shutdown_manager = None
# Windows-spezifisches Signal-Handling als Fallback
def fallback_signal_handler(sig, frame):
"""Fallback Signal-Handler für ordnungsgemäßes Shutdown."""
app_logger.warning(f"🛑 Signal {sig} empfangen - fahre System herunter (Fallback)...")
try:
# Queue Manager stoppen
stop_queue_manager()
# Scheduler stoppen falls aktiviert
if SCHEDULER_ENABLED and scheduler:
try:
if hasattr(scheduler, 'shutdown'):
scheduler.shutdown(wait=True)
else:
scheduler.stop()
except Exception as e:
app_logger.error(f"Fehler beim Stoppen des Schedulers: {str(e)}")
app_logger.info("✅ Fallback-Shutdown abgeschlossen")
sys.exit(0)
except Exception as e:
app_logger.error(f"❌ Fehler beim Fallback-Shutdown: {str(e)}")
sys.exit(1)
# Signal-Handler registrieren (Windows-kompatibel)
if os.name == 'nt': # Windows
signal.signal(signal.SIGINT, fallback_signal_handler)
signal.signal(signal.SIGTERM, fallback_signal_handler)
signal.signal(signal.SIGBREAK, fallback_signal_handler)
else: # Unix/Linux
signal.signal(signal.SIGINT, fallback_signal_handler)
signal.signal(signal.SIGTERM, fallback_signal_handler)
signal.signal(signal.SIGHUP, fallback_signal_handler)
try:
# Datenbank initialisieren und Migrationen durchführen
@ -6643,6 +6607,25 @@ if __name__ == "__main__":
except Exception as e:
app_logger.error(f"❌ Fehler bei automatischer Steckdosen-Initialisierung: {str(e)}")
# ===== SHUTDOWN-MANAGER KONFIGURATION =====
if shutdown_manager:
# Queue Manager beim Shutdown-Manager registrieren
try:
import utils.queue_manager as queue_module
shutdown_manager.register_queue_manager(queue_module)
app_logger.debug("✅ Queue Manager beim Shutdown-Manager registriert")
except Exception as e:
app_logger.warning(f"⚠️ Queue Manager Registrierung fehlgeschlagen: {e}")
# Scheduler beim Shutdown-Manager registrieren
shutdown_manager.register_scheduler(scheduler, SCHEDULER_ENABLED)
# Datenbank-Cleanup beim Shutdown-Manager registrieren
shutdown_manager.register_database_cleanup()
# Windows Thread Manager beim Shutdown-Manager registrieren
shutdown_manager.register_windows_thread_manager()
# Queue-Manager für automatische Drucker-Überwachung starten
# Nur im Produktionsmodus starten (nicht im Debug-Modus)
if not debug_mode:
@ -6650,61 +6633,6 @@ if __name__ == "__main__":
queue_manager = start_queue_manager()
app_logger.info("✅ Printer Queue Manager erfolgreich gestartet")
# Verbesserte Shutdown-Handler registrieren
def cleanup_queue_manager():
try:
app_logger.info("🔄 Beende Queue Manager...")
stop_queue_manager()
except Exception as e:
app_logger.error(f"❌ Fehler beim Queue Manager Cleanup: {str(e)}")
atexit.register(cleanup_queue_manager)
# ===== ROBUSTES DATENBANK-CLEANUP BEIM PROGRAMMENDE =====
def cleanup_database():
"""Führt robustes Datenbank-Cleanup beim normalen Programmende aus."""
try:
app_logger.info("💾 Führe finales robustes Datenbank-Cleanup durch...")
# Verwende den neuen DatabaseCleanupManager
try:
from utils.database_cleanup import safe_database_cleanup
# Führe umfassendes, sicheres Cleanup durch
cleanup_result = safe_database_cleanup(force_mode_switch=True)
if cleanup_result["success"]:
app_logger.info(f"✅ Finales Datenbank-Cleanup erfolgreich: {', '.join(cleanup_result['operations'])}")
if cleanup_result.get("wal_files_removed", False):
app_logger.info("✅ WAL- und SHM-Dateien erfolgreich entfernt")
else:
app_logger.warning(f"⚠️ Finales Datenbank-Cleanup mit Problemen: {', '.join(cleanup_result['errors'])}")
except ImportError:
# Fallback auf die alte Methode falls Cleanup-Manager nicht verfügbar
app_logger.warning("Fallback: Verwende Legacy-finales-Datenbank-Cleanup...")
from models import create_optimized_engine
from sqlalchemy import text
engine = create_optimized_engine()
with engine.connect() as conn:
# Nur WAL-Checkpoint - kein risikoreicher Mode-Switch
result = conn.execute(text("PRAGMA wal_checkpoint(TRUNCATE)")).fetchone()
if result and result[1] > 0:
app_logger.info(f"Final WAL-Checkpoint: {result[1]} Seiten übertragen")
conn.commit()
# Connection-Pool ordnungsgemäß schließen
engine.dispose()
app_logger.info("✅ Legacy-finales Datenbank-Cleanup abgeschlossen")
except Exception as e:
app_logger.error(f"❌ Fehler beim finalen robusten Datenbank-Cleanup: {str(e)}")
atexit.register(cleanup_database)
except Exception as e:
app_logger.error(f"❌ Fehler beim Starten des Queue-Managers: {str(e)}")
else:
@ -6760,12 +6688,18 @@ if __name__ == "__main__":
)
except KeyboardInterrupt:
app_logger.info("🔄 Tastatur-Unterbrechung empfangen - beende Anwendung...")
signal_handler(signal.SIGINT, None)
if shutdown_manager:
shutdown_manager.shutdown()
else:
fallback_signal_handler(signal.SIGINT, None)
except Exception as e:
app_logger.error(f"Fehler beim Starten der Anwendung: {str(e)}")
# Cleanup bei Fehler
try:
stop_queue_manager()
except:
pass
sys.exit(1)
if shutdown_manager:
shutdown_manager.force_shutdown(1)
else:
try:
stop_queue_manager()
except:
pass
sys.exit(1)