🎉 Improved backend functionality & documentation, optimized database files, and introduced shutdown management 🧹
This commit is contained in:
214
backend/app.py
214
backend/app.py
@ -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)
|
||||
|
Reference in New Issue
Block a user