647 lines
23 KiB
Python
647 lines
23 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Timeout Force-Quit Manager mit Terminal-Countdown
|
|
|
|
Spezialiserter Manager für Force-Quit-Timeouts mit visueller Terminal-Anzeige
|
|
und robuster Datenbankbereinigung (WAL/SHM-Dateien).
|
|
|
|
Funktionen:
|
|
- Terminal-Countdown mit Fortschrittsbalken
|
|
- Automatische Datenbankbereinigung
|
|
- Force-Quit bei Timeout
|
|
- Integration mit bestehendem Timer-System
|
|
- Robuste WAL/SHM-Dateibereinigung
|
|
|
|
Autor: System
|
|
Erstellt: 2025
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import threading
|
|
import time
|
|
import signal
|
|
import shutil
|
|
from datetime import datetime, timedelta
|
|
from typing import Optional, Callable, Dict, Any
|
|
from contextlib import contextmanager
|
|
|
|
# Logging
|
|
try:
|
|
from utils.logging_config import get_logger
|
|
logger = get_logger("timeout_force_quit")
|
|
except ImportError:
|
|
import logging
|
|
logger = logging.getLogger("timeout_force_quit")
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
# Timer-System Integration
|
|
try:
|
|
from utils.timer_manager import (
|
|
get_timer_manager, TimerType, ForceQuitAction, TimerStatus
|
|
)
|
|
from models import SystemTimer, get_cached_session
|
|
TIMER_SYSTEM_AVAILABLE = True
|
|
except ImportError:
|
|
logger.warning("Timer-System nicht verfügbar - verwende Fallback-Implementation")
|
|
TIMER_SYSTEM_AVAILABLE = False
|
|
|
|
# Datenbank-Cleanup
|
|
try:
|
|
from utils.database_cleanup import safe_database_cleanup
|
|
DATABASE_CLEANUP_AVAILABLE = True
|
|
except ImportError:
|
|
logger.warning("Database-Cleanup-Manager nicht verfügbar - verwende Basis-Cleanup")
|
|
DATABASE_CLEANUP_AVAILABLE = False
|
|
|
|
|
|
class TimeoutForceQuitManager:
|
|
"""
|
|
Manager für Timeout-basierte Force-Quit-Operationen mit Terminal-Countdown.
|
|
|
|
Bietet:
|
|
- Visueller Terminal-Countdown
|
|
- Automatische Datenbankbereinigung
|
|
- Robuste WAL/SHM-Dateibereinigung
|
|
- Konfigurierbare Timeout-Aktionen
|
|
"""
|
|
|
|
def __init__(self,
|
|
timeout_seconds: int = 45,
|
|
warning_seconds: int = 15,
|
|
database_cleanup: bool = True,
|
|
force_wal_cleanup: bool = True):
|
|
"""
|
|
Initialisiert den Timeout Force-Quit Manager.
|
|
|
|
Args:
|
|
timeout_seconds: Gesamttimeout in Sekunden
|
|
warning_seconds: Warnzeit vor Force-Quit in Sekunden
|
|
database_cleanup: Datenbankbereinigung aktivieren
|
|
force_wal_cleanup: Aggressive WAL/SHM-Bereinigung
|
|
"""
|
|
self.timeout_seconds = timeout_seconds
|
|
self.warning_seconds = warning_seconds
|
|
self.database_cleanup = database_cleanup
|
|
self.force_wal_cleanup = force_wal_cleanup
|
|
|
|
# Countdown-Status
|
|
self.is_active = False
|
|
self.start_time = None
|
|
self.timer_thread = None
|
|
self.countdown_thread = None
|
|
self.shutdown_callback: Optional[Callable] = None
|
|
|
|
# Terminal-Kontrolle
|
|
self.show_terminal_countdown = True
|
|
self.terminal_lock = threading.Lock()
|
|
|
|
logger.info(f"🔧 Timeout Force-Quit Manager initialisiert - Timeout: {timeout_seconds}s, Warnung: {warning_seconds}s")
|
|
|
|
def set_shutdown_callback(self, callback: Callable):
|
|
"""Setzt eine Callback-Funktion für den Shutdown"""
|
|
self.shutdown_callback = callback
|
|
logger.debug("Shutdown-Callback registriert")
|
|
|
|
def start_timeout(self, reason: str = "System-Timeout") -> bool:
|
|
"""
|
|
Startet den Timeout-Countdown.
|
|
|
|
Args:
|
|
reason: Grund für den Timeout
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich gestartet
|
|
"""
|
|
if self.is_active:
|
|
logger.warning("Timeout bereits aktiv")
|
|
return False
|
|
|
|
try:
|
|
self.is_active = True
|
|
self.start_time = datetime.now()
|
|
|
|
logger.warning(f"🚨 TIMEOUT GESTARTET - {reason}")
|
|
logger.warning(f"⏱️ Force-Quit in {self.timeout_seconds} Sekunden")
|
|
|
|
# Timer für Force-Quit
|
|
self.timer_thread = threading.Thread(
|
|
target=self._timeout_worker,
|
|
args=(reason,),
|
|
name="TimeoutForceQuit-Timer",
|
|
daemon=True
|
|
)
|
|
self.timer_thread.start()
|
|
|
|
# Terminal-Countdown (nur wenn stdout verfügbar)
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
self.countdown_thread = threading.Thread(
|
|
target=self._terminal_countdown_worker,
|
|
name="TimeoutForceQuit-Countdown",
|
|
daemon=True
|
|
)
|
|
self.countdown_thread.start()
|
|
|
|
# Integration mit Timer-System falls verfügbar
|
|
if TIMER_SYSTEM_AVAILABLE:
|
|
self._create_system_timer(reason)
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler beim Starten des Timeouts: {e}")
|
|
self.is_active = False
|
|
return False
|
|
|
|
def cancel_timeout(self) -> bool:
|
|
"""
|
|
Bricht den laufenden Timeout ab.
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich abgebrochen
|
|
"""
|
|
if not self.is_active:
|
|
return False
|
|
|
|
try:
|
|
self.is_active = False
|
|
|
|
logger.info("✅ Timeout abgebrochen")
|
|
|
|
# Terminal-Ausgabe löschen
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
with self.terminal_lock:
|
|
print("\r" + " " * 80 + "\r", end="", flush=True)
|
|
print("✅ Timeout abgebrochen")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler beim Abbrechen des Timeouts: {e}")
|
|
return False
|
|
|
|
def extend_timeout(self, additional_seconds: int) -> bool:
|
|
"""
|
|
Verlängert den laufenden Timeout.
|
|
|
|
Args:
|
|
additional_seconds: Zusätzliche Sekunden
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich verlängert
|
|
"""
|
|
if not self.is_active:
|
|
logger.warning("Kein aktiver Timeout zum Verlängern")
|
|
return False
|
|
|
|
try:
|
|
self.timeout_seconds += additional_seconds
|
|
logger.info(f"⏰ Timeout um {additional_seconds} Sekunden verlängert")
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler beim Verlängern des Timeouts: {e}")
|
|
return False
|
|
|
|
def _timeout_worker(self, reason: str):
|
|
"""Worker-Thread für den eigentlichen Timeout"""
|
|
try:
|
|
# Warte bis zum Timeout
|
|
time.sleep(self.timeout_seconds)
|
|
|
|
if self.is_active:
|
|
logger.critical(f"🚨 FORCE-QUIT TIMEOUT ERREICHT - {reason}")
|
|
self._execute_force_quit()
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler im Timeout-Worker: {e}")
|
|
|
|
def _terminal_countdown_worker(self):
|
|
"""Worker-Thread für den visuellen Terminal-Countdown"""
|
|
try:
|
|
while self.is_active:
|
|
elapsed = (datetime.now() - self.start_time).total_seconds()
|
|
remaining = max(0, self.timeout_seconds - elapsed)
|
|
|
|
if remaining <= 0:
|
|
break
|
|
|
|
# Fortschrittsbalken und Countdown
|
|
progress = 1.0 - (remaining / self.timeout_seconds)
|
|
bar_width = 40
|
|
filled_width = int(bar_width * progress)
|
|
|
|
# Warnung-Status
|
|
is_warning = remaining <= self.warning_seconds
|
|
warning_icon = "🚨" if is_warning else "⏳"
|
|
|
|
# Terminal-Ausgabe mit Lock
|
|
with self.terminal_lock:
|
|
bar = "█" * filled_width + "░" * (bar_width - filled_width)
|
|
countdown_text = (
|
|
f"\r{warning_icon} FORCE-QUIT in: {int(remaining):3d}s "
|
|
f"[{bar}] {progress*100:6.1f}% "
|
|
)
|
|
print(countdown_text, end="", flush=True)
|
|
|
|
# Warnung ausgeben
|
|
if is_warning and int(remaining) % 5 == 0:
|
|
logger.warning(f"⚠️ WARNUNG: Force-Quit in {int(remaining)} Sekunden!")
|
|
|
|
time.sleep(0.1) # 100ms Update-Intervall
|
|
|
|
# Letzte Ausgabe
|
|
if self.is_active:
|
|
with self.terminal_lock:
|
|
print("\r🚨 FORCE-QUIT WIRD AUSGEFÜHRT!" + " " * 30, flush=True)
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler im Terminal-Countdown: {e}")
|
|
|
|
def _create_system_timer(self, reason: str):
|
|
"""Erstellt einen System-Timer für Integration mit bestehendem Timer-System"""
|
|
try:
|
|
timer_manager = get_timer_manager()
|
|
|
|
timer_name = f"force_quit_{int(time.time())}"
|
|
|
|
timer = timer_manager.create_timer(
|
|
name=timer_name,
|
|
timer_type=TimerType.SYSTEM,
|
|
duration_seconds=self.timeout_seconds,
|
|
force_quit_action=ForceQuitAction.SHUTDOWN,
|
|
auto_start=True,
|
|
warning_message=f"Force-Quit wegen: {reason}",
|
|
force_quit_warning_seconds=self.warning_seconds
|
|
)
|
|
|
|
if timer:
|
|
logger.debug(f"System-Timer '{timer_name}' erstellt")
|
|
|
|
except Exception as e:
|
|
logger.warning(f"System-Timer konnte nicht erstellt werden: {e}")
|
|
|
|
def _execute_force_quit(self):
|
|
"""Führt den Force-Quit aus"""
|
|
try:
|
|
logger.critical("🚨 FORCE-QUIT WIRD AUSGEFÜHRT")
|
|
|
|
# Terminal-Ausgabe stoppen
|
|
self.is_active = False
|
|
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
with self.terminal_lock:
|
|
print("\r🚨 FORCE-QUIT AKTIV - DATENBANKBEREINIGUNG..." + " " * 20, flush=True)
|
|
|
|
# 1. Shutdown-Callback ausführen (falls gesetzt)
|
|
if self.shutdown_callback:
|
|
try:
|
|
logger.info("📞 Führe Shutdown-Callback aus...")
|
|
self.shutdown_callback()
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler im Shutdown-Callback: {e}")
|
|
|
|
# 2. Datenbankbereinigung
|
|
if self.database_cleanup:
|
|
self._perform_database_cleanup()
|
|
|
|
# 3. System beenden
|
|
logger.critical("💀 FORCE-QUIT ABGESCHLOSSEN - SYSTEM WIRD BEENDET")
|
|
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
with self.terminal_lock:
|
|
print("💀 FORCE-QUIT ABGESCHLOSSEN", flush=True)
|
|
|
|
# Kurze Verzögerung für Log-Ausgabe
|
|
time.sleep(1)
|
|
|
|
# System beenden
|
|
os._exit(1)
|
|
|
|
except Exception as e:
|
|
logger.critical(f"❌ KRITISCHER FEHLER IM FORCE-QUIT: {e}")
|
|
# Notfall-Exit
|
|
os._exit(1)
|
|
|
|
def _perform_database_cleanup(self):
|
|
"""Führt robuste Datenbankbereinigung durch"""
|
|
try:
|
|
logger.info("💾 Starte Datenbankbereinigung...")
|
|
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
with self.terminal_lock:
|
|
print("\r💾 Datenbankbereinigung läuft..." + " " * 30, flush=True)
|
|
|
|
# 1. Verwende modernen DatabaseCleanupManager falls verfügbar
|
|
if DATABASE_CLEANUP_AVAILABLE:
|
|
logger.info("🔧 Verwende DatabaseCleanupManager...")
|
|
result = safe_database_cleanup(
|
|
force_mode_switch=True, # Aggressive Bereinigung
|
|
max_cleanup_time=10 # 10 Sekunden Maximum
|
|
)
|
|
|
|
if result.get("success", False):
|
|
logger.info(f"✅ Database-Cleanup erfolgreich: {', '.join(result.get('operations', []))}")
|
|
else:
|
|
logger.warning(f"⚠️ Database-Cleanup mit Problemen: {', '.join(result.get('errors', []))}")
|
|
# Fallback verwenden
|
|
self._fallback_database_cleanup()
|
|
else:
|
|
# 2. Fallback: Direkter SQLite-Cleanup
|
|
self._fallback_database_cleanup()
|
|
|
|
# 3. WAL/SHM-Dateien manuell bereinigen falls gewünscht
|
|
if self.force_wal_cleanup:
|
|
self._force_wal_shm_cleanup()
|
|
|
|
logger.info("✅ Datenbankbereinigung abgeschlossen")
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler bei Datenbankbereinigung: {e}")
|
|
# Versuche trotzdem WAL/SHM-Cleanup
|
|
if self.force_wal_cleanup:
|
|
try:
|
|
self._force_wal_shm_cleanup()
|
|
except:
|
|
pass
|
|
|
|
def _fallback_database_cleanup(self):
|
|
"""Fallback-Datenbankbereinigung mit direkten SQLite-Befehlen"""
|
|
try:
|
|
from models import create_optimized_engine
|
|
from sqlalchemy import text
|
|
|
|
logger.info("🔄 Fallback Database-Cleanup...")
|
|
|
|
engine = create_optimized_engine()
|
|
|
|
with engine.connect() as conn:
|
|
# WAL-Checkpoint (TRUNCATE für vollständige Bereinigung)
|
|
result = conn.execute(text("PRAGMA wal_checkpoint(TRUNCATE)")).fetchone()
|
|
if result and result[1] > 0:
|
|
logger.info(f"WAL-Checkpoint: {result[1]} Seiten übertragen")
|
|
|
|
# Alle ausstehenden Transaktionen committen
|
|
conn.commit()
|
|
|
|
# Verbindung optimieren
|
|
conn.execute(text("PRAGMA optimize"))
|
|
|
|
logger.info("✅ Fallback Database-Cleanup abgeschlossen")
|
|
|
|
# Engine ordnungsgemäß schließen
|
|
engine.dispose()
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler im Fallback Database-Cleanup: {e}")
|
|
|
|
def _force_wal_shm_cleanup(self):
|
|
"""Aggressive Bereinigung von WAL/SHM-Dateien"""
|
|
try:
|
|
from config.settings import DATABASE_PATH
|
|
|
|
logger.info("🧹 Force WAL/SHM-Cleanup...")
|
|
|
|
if self.show_terminal_countdown and sys.stdout.isatty():
|
|
with self.terminal_lock:
|
|
print("\r🧹 WAL/SHM-Dateien werden bereinigt..." + " " * 20, flush=True)
|
|
|
|
# Kurze Pause um sicherzustellen, dass alle DB-Verbindungen geschlossen sind
|
|
time.sleep(0.5)
|
|
|
|
# WAL-Datei
|
|
wal_path = DATABASE_PATH + "-wal"
|
|
if os.path.exists(wal_path):
|
|
try:
|
|
# Versuche erst normales Löschen
|
|
os.remove(wal_path)
|
|
logger.info(f"✅ WAL-Datei gelöscht: {wal_path}")
|
|
except OSError:
|
|
# Falls blockiert, versuche Umbenennung und Löschung
|
|
try:
|
|
backup_path = wal_path + f".backup_{int(time.time())}"
|
|
shutil.move(wal_path, backup_path)
|
|
os.remove(backup_path)
|
|
logger.info(f"✅ WAL-Datei über Backup gelöscht: {wal_path}")
|
|
except Exception as e:
|
|
logger.warning(f"⚠️ WAL-Datei konnte nicht gelöscht werden: {e}")
|
|
|
|
# SHM-Datei
|
|
shm_path = DATABASE_PATH + "-shm"
|
|
if os.path.exists(shm_path):
|
|
try:
|
|
os.remove(shm_path)
|
|
logger.info(f"✅ SHM-Datei gelöscht: {shm_path}")
|
|
except OSError:
|
|
try:
|
|
backup_path = shm_path + f".backup_{int(time.time())}"
|
|
shutil.move(shm_path, backup_path)
|
|
os.remove(backup_path)
|
|
logger.info(f"✅ SHM-Datei über Backup gelöscht: {shm_path}")
|
|
except Exception as e:
|
|
logger.warning(f"⚠️ SHM-Datei konnte nicht gelöscht werden: {e}")
|
|
|
|
logger.info("✅ Force WAL/SHM-Cleanup abgeschlossen")
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ Fehler bei Force WAL/SHM-Cleanup: {e}")
|
|
|
|
def get_status(self) -> Dict[str, Any]:
|
|
"""Gibt den aktuellen Status zurück"""
|
|
if not self.is_active:
|
|
return {
|
|
"active": False,
|
|
"remaining_seconds": 0,
|
|
"progress_percent": 0.0
|
|
}
|
|
|
|
elapsed = (datetime.now() - self.start_time).total_seconds()
|
|
remaining = max(0, self.timeout_seconds - elapsed)
|
|
progress = 1.0 - (remaining / self.timeout_seconds) if self.timeout_seconds > 0 else 1.0
|
|
|
|
return {
|
|
"active": True,
|
|
"remaining_seconds": int(remaining),
|
|
"progress_percent": round(progress * 100, 1),
|
|
"is_warning": remaining <= self.warning_seconds,
|
|
"start_time": self.start_time.isoformat() if self.start_time else None
|
|
}
|
|
|
|
|
|
# ===== GLOBALER MANAGER UND UTILITY-FUNKTIONEN =====
|
|
|
|
_timeout_manager: Optional[TimeoutForceQuitManager] = None
|
|
_manager_lock = threading.Lock()
|
|
|
|
|
|
def get_timeout_manager(timeout_seconds: int = 45,
|
|
warning_seconds: int = 15,
|
|
database_cleanup: bool = True,
|
|
force_wal_cleanup: bool = True) -> TimeoutForceQuitManager:
|
|
"""
|
|
Singleton-Pattern für globalen Timeout-Manager.
|
|
|
|
Args:
|
|
timeout_seconds: Gesamttimeout in Sekunden
|
|
warning_seconds: Warnzeit vor Force-Quit
|
|
database_cleanup: Datenbankbereinigung aktivieren
|
|
force_wal_cleanup: Aggressive WAL/SHM-Bereinigung
|
|
|
|
Returns:
|
|
TimeoutForceQuitManager: Globaler Timeout-Manager
|
|
"""
|
|
global _timeout_manager
|
|
|
|
with _manager_lock:
|
|
if _timeout_manager is None:
|
|
_timeout_manager = TimeoutForceQuitManager(
|
|
timeout_seconds=timeout_seconds,
|
|
warning_seconds=warning_seconds,
|
|
database_cleanup=database_cleanup,
|
|
force_wal_cleanup=force_wal_cleanup
|
|
)
|
|
|
|
return _timeout_manager
|
|
|
|
|
|
def start_force_quit_timeout(reason: str = "System-Timeout",
|
|
timeout_seconds: int = 45,
|
|
warning_seconds: int = 15,
|
|
database_cleanup: bool = True,
|
|
force_wal_cleanup: bool = True) -> bool:
|
|
"""
|
|
Startet einen Force-Quit-Timeout mit Terminal-Countdown.
|
|
|
|
Args:
|
|
reason: Grund für den Timeout
|
|
timeout_seconds: Gesamttimeout in Sekunden
|
|
warning_seconds: Warnzeit vor Force-Quit
|
|
database_cleanup: Datenbankbereinigung aktivieren
|
|
force_wal_cleanup: Aggressive WAL/SHM-Bereinigung
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich gestartet
|
|
"""
|
|
manager = get_timeout_manager(timeout_seconds, warning_seconds, database_cleanup, force_wal_cleanup)
|
|
return manager.start_timeout(reason)
|
|
|
|
|
|
def cancel_force_quit_timeout() -> bool:
|
|
"""
|
|
Bricht den aktuellen Force-Quit-Timeout ab.
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich abgebrochen
|
|
"""
|
|
global _timeout_manager
|
|
|
|
if _timeout_manager:
|
|
return _timeout_manager.cancel_timeout()
|
|
|
|
return False
|
|
|
|
|
|
def extend_force_quit_timeout(additional_seconds: int) -> bool:
|
|
"""
|
|
Verlängert den aktuellen Force-Quit-Timeout.
|
|
|
|
Args:
|
|
additional_seconds: Zusätzliche Sekunden
|
|
|
|
Returns:
|
|
bool: True wenn erfolgreich verlängert
|
|
"""
|
|
global _timeout_manager
|
|
|
|
if _timeout_manager:
|
|
return _timeout_manager.extend_timeout(additional_seconds)
|
|
|
|
return False
|
|
|
|
|
|
def get_force_quit_status() -> Dict[str, Any]:
|
|
"""
|
|
Gibt den Status des aktuellen Force-Quit-Timeouts zurück.
|
|
|
|
Returns:
|
|
Dict: Status-Informationen
|
|
"""
|
|
global _timeout_manager
|
|
|
|
if _timeout_manager:
|
|
return _timeout_manager.get_status()
|
|
|
|
return {"active": False, "remaining_seconds": 0, "progress_percent": 0.0}
|
|
|
|
|
|
@contextmanager
|
|
def timeout_context(timeout_seconds: int = 45,
|
|
reason: str = "Operation-Timeout",
|
|
auto_cancel: bool = True):
|
|
"""
|
|
Context-Manager für automatischen Timeout-Schutz.
|
|
|
|
Args:
|
|
timeout_seconds: Timeout in Sekunden
|
|
reason: Grund für den Timeout
|
|
auto_cancel: Automatisch abbrechen beim Verlassen des Contexts
|
|
|
|
Usage:
|
|
with timeout_context(30, "Datenbank-Migration"):
|
|
# Lange Operation...
|
|
pass
|
|
"""
|
|
manager = get_timeout_manager(timeout_seconds)
|
|
success = manager.start_timeout(reason)
|
|
|
|
try:
|
|
yield manager
|
|
finally:
|
|
if success and auto_cancel:
|
|
manager.cancel_timeout()
|
|
|
|
|
|
def register_shutdown_callback(callback: Callable):
|
|
"""
|
|
Registriert eine Callback-Funktion für den Shutdown.
|
|
|
|
Args:
|
|
callback: Callback-Funktion die beim Shutdown ausgeführt wird
|
|
"""
|
|
manager = get_timeout_manager()
|
|
manager.set_shutdown_callback(callback)
|
|
|
|
|
|
# ===== INTEGRATION MIT SHUTDOWN-MANAGER =====
|
|
|
|
def integrate_with_shutdown_manager():
|
|
"""Integriert den Timeout-Manager mit dem bestehenden Shutdown-Manager"""
|
|
try:
|
|
from utils.shutdown_manager import get_shutdown_manager
|
|
|
|
shutdown_manager = get_shutdown_manager()
|
|
|
|
# Force-Quit-Timeout als Cleanup-Funktion registrieren
|
|
def timeout_cleanup():
|
|
global _timeout_manager
|
|
if _timeout_manager and _timeout_manager.is_active:
|
|
logger.info("🔄 Timeout-Manager wird im Shutdown-Prozess gestoppt")
|
|
_timeout_manager.cancel_timeout()
|
|
|
|
shutdown_manager.register_cleanup_function(
|
|
func=timeout_cleanup,
|
|
name="Timeout Force-Quit Manager",
|
|
priority=1, # Hohe Priorität
|
|
timeout=5
|
|
)
|
|
|
|
logger.debug("✅ Timeout-Manager in Shutdown-Manager integriert")
|
|
|
|
except ImportError:
|
|
logger.debug("Shutdown-Manager nicht verfügbar - keine Integration")
|
|
except Exception as e:
|
|
logger.warning(f"Fehler bei Shutdown-Manager-Integration: {e}")
|
|
|
|
|
|
# Automatische Integration beim Import
|
|
integrate_with_shutdown_manager() |