From 089095e0710892d1b57f441ba341eb555316da42 Mon Sep 17 00:00:00 2001 From: SimolZimol <70102430+SimolZimol@users.noreply.github.com> Date: Sun, 24 Aug 2025 01:05:03 +0200 Subject: [PATCH] modified: app.py --- app.py | 202 +++++---------------------------------------------------- 1 file changed, 18 insertions(+), 184 deletions(-) diff --git a/app.py b/app.py index 92d5b99..fb33e1b 100644 --- a/app.py +++ b/app.py @@ -8,11 +8,9 @@ import os import subprocess import psutil import mysql.connector -from mysql.connector import pooling from datetime import datetime, timedelta from flask_session import Session import logging -import time app = Flask(__name__) app.secret_key = os.getenv("FLASK_SECRET_KEY") @@ -52,45 +50,6 @@ DB_USER = os.getenv("DB_USER") DB_PASS = os.getenv("DB_PASSWORD") DB_NAME = os.getenv("DB_DATABASE") -# Connection Pool Konfiguration -DB_POOL_CONFIG = { - 'pool_name': 'multus_pool', - 'pool_size': 5, - 'pool_reset_session': True, - 'host': DB_HOST, - 'port': DB_PORT, - 'user': DB_USER, - 'password': DB_PASS, - 'database': DB_NAME, - 'autocommit': True, - 'connection_timeout': 20, - 'charset': 'utf8mb4', - 'collation': 'utf8mb4_unicode_ci', - 'buffered': True, - 'raise_on_warnings': False, - 'use_unicode': True, - 'sql_mode': '', - 'max_allowed_packet': 16777216, - 'auth_plugin': 'mysql_native_password' -} - -# Globaler Connection Pool -db_pool = None - -def initialize_db_pool(): - """Initialisiert den Datenbankverbindungspool.""" - global db_pool - try: - db_pool = pooling.MySQLConnectionPool(**DB_POOL_CONFIG) - print("✅ Datenbankverbindungspool erfolgreich initialisiert") - return True - except mysql.connector.Error as err: - print(f"❌ Fehler beim Initialisieren des Datenbankpools: {err}") - return False - except Exception as err: - print(f"❌ Unerwarteter Fehler beim Pool-Setup: {err}") - return False - DISCORD_CLIENT_ID = os.getenv("DISCORD_CLIENT_ID") DISCORD_CLIENT_SECRET = os.getenv("DISCORD_CLIENT_SECRET") DISCORD_REDIRECT_URI = os.getenv("DISCORD_REDIRECT_URI") @@ -140,74 +99,32 @@ def test_db_connection(): return False def safe_db_operation(operation_func, *args, **kwargs): - """Führt eine Datenbankoperation sicher aus mit Fehlerbehandlung und automatischem Connection-Management.""" - connection = None - cursor = None + """Führt eine Datenbankoperation sicher aus mit Fehlerbehandlung.""" try: connection = get_db_connection() cursor = connection.cursor(dictionary=True) result = operation_func(cursor, *args, **kwargs) - # Commit falls nötig (auch wenn autocommit=True ist) - if connection.in_transaction: - connection.commit() - + cursor.close() + connection.close() + return result - except mysql.connector.Error as err: - print(f"Datenbankfehler in safe_db_operation: {err}") - if connection and connection.in_transaction: - try: - connection.rollback() - except: - pass + print(f"Datenbankfehler: {err}") return None - except Exception as err: print(f"Unerwarteter Fehler bei Datenbankoperation: {err}") - if connection and connection.in_transaction: - try: - connection.rollback() - except: - pass return None - - finally: - # Ressourcen sauber freigeben - if cursor: - try: - cursor.close() - except: - pass - if connection: - try: - if connection.is_connected(): - connection.close() - except: - pass def get_db_connection(): - """Holt eine Verbindung aus dem Connection Pool mit Fallback.""" - global db_pool + """Stellt eine Verbindung zur MySQL-Datenbank her mit Retry-Mechanismus.""" + import time max_retries = 3 - retry_delay = 1 + retry_delay = 1 # Sekunden for attempt in range(max_retries): try: - # Versuche zuerst den Pool zu verwenden - if db_pool: - connection = db_pool.get_connection() - if connection.is_connected(): - # Test die Verbindung - cursor = connection.cursor() - cursor.execute("SELECT 1") - cursor.fetchone() - cursor.close() - return connection - - # Fallback: Direkte Verbindung ohne Pool - print(f"Pool nicht verfügbar, verwende direkte Verbindung (Versuch {attempt + 1})") connection = mysql.connector.connect( host=DB_HOST, port=DB_PORT, @@ -215,42 +132,22 @@ def get_db_connection(): password=DB_PASS, database=DB_NAME, autocommit=True, - connection_timeout=20, + connection_timeout=10, reconnect=True, charset='utf8mb4', - collation='utf8mb4_unicode_ci', - buffered=True, - raise_on_warnings=False, - use_unicode=True, - sql_mode='', - max_allowed_packet=16777216, - auth_plugin='mysql_native_password' + collation='utf8mb4_unicode_ci' ) - + # Test the connection if connection.is_connected(): - cursor = connection.cursor() - cursor.execute("SELECT 1") - cursor.fetchone() - cursor.close() return connection - except mysql.connector.Error as err: print(f"Datenbankverbindung Versuch {attempt + 1} fehlgeschlagen: {err}") - if err.errno == 2013: - print("⚠️ Spezifischer Fehler: Kommunikationspakete verloren - Netzwerkproblem") - elif err.errno == 2003: - print("⚠️ Spezifischer Fehler: Kann MySQL-Server nicht erreichen") - elif err.errno == 1045: - print("⚠️ Spezifischer Fehler: Authentifizierung fehlgeschlagen") - if attempt < max_retries - 1: - print(f"Warte {retry_delay} Sekunden vor nächstem Versuch...") time.sleep(retry_delay) - retry_delay *= 2 + retry_delay *= 2 # Exponential backoff else: - print("❌ Alle Datenbankverbindungsversuche fehlgeschlagen") + print("Alle Datenbankverbindungsversuche fehlgeschlagen") raise - except Exception as err: print(f"Unerwarteter Fehler bei Datenbankverbindung: {err}") if attempt < max_retries - 1: @@ -383,8 +280,6 @@ def load_user_data(): g.bot_running = bot_status() # Lädt den Bot-Status in g # Hole die Liste der Gilden aus der Datenbank - connection = None - cursor = None try: connection = get_db_connection() cursor = connection.cursor(dictionary=True) @@ -395,16 +290,16 @@ def load_user_data(): if user_guild_ids: # Finde nur die Gilden, die auch in der Datenbank existieren - placeholders = ','.join(['%s'] * len(user_guild_ids)) - query = f"SELECT guild_id FROM guilds WHERE guild_id IN ({placeholders})" - cursor.execute(query, user_guild_ids) + cursor.execute("SELECT guild_id FROM guilds WHERE guild_id IN (%s)" % ','.join(['%s'] * len(user_guild_ids)), user_guild_ids) existing_guilds = cursor.fetchall() # Filtere die Gilden des Nutzers basierend auf der Existenz in der Datenbank - existing_guild_ids = {g["guild_id"] for g in existing_guilds} - g.guilds = [guild for guild in user_guilds if int(guild["id"]) in existing_guild_ids] + g.guilds = [guild for guild in user_guilds if int(guild["id"]) in {g["guild_id"] for g in existing_guilds}] else: g.guilds = [] + + cursor.close() + connection.close() except mysql.connector.Error as err: print(f"Datenbankfehler in load_user_data: {err}") @@ -412,19 +307,6 @@ def load_user_data(): except Exception as err: print(f"Unerwarteter Fehler in load_user_data: {err}") g.guilds = [] # Fallback auf leere Liste - finally: - # Ressourcen sauber freigeben - if cursor: - try: - cursor.close() - except: - pass - if connection: - try: - if connection.is_connected(): - connection.close() - except: - pass else: # Falls der Benutzer nicht eingeloggt ist, keine Daten setzen g.user_info = None @@ -1002,23 +884,13 @@ def stop(): @app.route("/health") def health_check(): """Health-Check-Endpunkt für die Anwendung und Datenbank.""" - global db_pool health_status = { "status": "healthy", "timestamp": datetime.now().isoformat(), "database": "disconnected", - "connection_pool": "not_initialized", "version": __version__ } - # Prüfe Connection Pool Status - if db_pool: - try: - health_status["connection_pool"] = "active" - health_status["pool_size"] = db_pool.pool_size - except: - health_status["connection_pool"] = "error" - # Teste die Datenbankverbindung if test_db_connection(): health_status["database"] = "connected" @@ -1028,45 +900,12 @@ def health_check(): health_status["database"] = "error" return jsonify(health_status), 503 -@app.route("/db_stats") -def db_stats(): - """Zeigt Datenbankstatistiken an (nur für Admins).""" - if not g.get('is_admin', False): - return jsonify({"error": "Unauthorized"}), 403 - - global db_pool - stats = { - "timestamp": datetime.now().isoformat(), - "pool_status": "not_initialized", - "version": __version__ - } - - if db_pool: - try: - stats.update({ - "pool_status": "active", - "pool_name": db_pool.pool_name, - "pool_size": db_pool.pool_size, - "pool_reset_session": DB_POOL_CONFIG.get('pool_reset_session', False) - }) - except Exception as e: - stats["pool_status"] = f"error: {str(e)}" - - return jsonify(stats) - if __name__ == "__main__": # Disable default Flask logging for static files app.logger.disabled = True log = logging.getLogger('werkzeug') log.disabled = True - # Initialisiere Datenbankverbindungspool - print("Initialisiere Datenbankverbindungspool...") - if initialize_db_pool(): - print("✅ Connection Pool erfolgreich erstellt!") - else: - print("⚠️ Connection Pool konnte nicht erstellt werden, verwende direkte Verbindungen") - # Test database connection on startup print("Teste Datenbankverbindung beim Start...") if test_db_connection(): @@ -1074,11 +913,6 @@ if __name__ == "__main__": else: print("❌ Datenbankverbindung fehlgeschlagen! Überprüfe die Konfiguration.") print("Die Anwendung wird trotzdem gestartet, aber Datenbankfunktionen sind nicht verfügbar.") - print("Häufige Ursachen:") - print(" - MySQL-Server ist nicht erreichbar") - print(" - Firewall blockiert die Verbindung") - print(" - Falsche Verbindungsparameter") - print(" - Netzwerkprobleme zwischen Client und Server") # Start app with minimal logging app.run(host="0.0.0.0", port=5000, debug=True)