modified: app.py

modified:   bot.py
This commit is contained in:
SimolZimol
2025-08-24 01:27:11 +02:00
parent 02dcde6f54
commit eb4ea0f6b8
2 changed files with 82 additions and 26 deletions

106
app.py
View File

@@ -7,6 +7,7 @@ from requests_oauthlib import OAuth2Session
import os import os
import subprocess import subprocess
import psutil import psutil
import time
import mysql.connector import mysql.connector
import mysql.connector.pooling import mysql.connector.pooling
from datetime import datetime, timedelta from datetime import datetime, timedelta
@@ -89,7 +90,7 @@ def stop_bot():
# Database Connection Pool für bessere Verbindungsverwaltung # Database Connection Pool für bessere Verbindungsverwaltung
app_pool = mysql.connector.pooling.MySQLConnectionPool( app_pool = mysql.connector.pooling.MySQLConnectionPool(
pool_name="app_pool", pool_name="app_pool",
pool_size=15, # Reduziert von 20 auf 15 (Bot: 30, App: 15 = max 45 statt 50+) pool_size=8, # Stark reduziert von 15 auf 8 (Bot: 25, App: 8 = 33 total)
pool_reset_session=True, pool_reset_session=True,
host=DB_HOST, host=DB_HOST,
port=DB_PORT, port=DB_PORT,
@@ -109,14 +110,24 @@ def get_db_connection():
return connection return connection
except mysql.connector.PoolError as e: except mysql.connector.PoolError as e:
print(f"Pool error in app.py: {e}") print(f"Pool error in app.py: {e}")
# Fallback zu direkter Verbindung bei Pool-Problemen # Besserer Fallback mit Retry-Mechanismus
return mysql.connector.connect( for attempt in range(3):
host=DB_HOST, try:
port=DB_PORT, print(f"Attempting direct connection (attempt {attempt + 1}/3)")
user=DB_USER, return mysql.connector.connect(
password=DB_PASS, host=DB_HOST,
database=DB_NAME port=DB_PORT,
) user=DB_USER,
password=DB_PASS,
database=DB_NAME,
connect_timeout=5,
autocommit=True
)
except Exception as retry_error:
print(f"Direct connection attempt {attempt + 1} failed: {retry_error}")
if attempt == 2: # Letzter Versuch
raise retry_error
time.sleep(1) # Kurze Pause zwischen Versuchen
from contextlib import contextmanager from contextlib import contextmanager
@@ -231,6 +242,24 @@ def landing_page():
"""Landing Page""" """Landing Page"""
return render_template("landing.html") return render_template("landing.html")
@app.route("/db_status")
def db_status():
"""Debug-Route für DB-Pool Status"""
try:
status = get_pool_status()
with get_db_cursor() as (cursor, connection):
cursor.execute("SELECT 1")
db_ok = True
except Exception as e:
status = {"error": str(e)}
db_ok = False
return jsonify({
"pool_status": status,
"database_ok": db_ok,
"timestamp": datetime.now().isoformat()
})
@app.route("/about") @app.route("/about")
def about(): def about():
"""Öffentliche Über-uns-Seite""" """Öffentliche Über-uns-Seite"""
@@ -268,29 +297,56 @@ def load_user_data():
g.is_admin = session.get("is_admin", False) g.is_admin = session.get("is_admin", False)
g.bot_running = bot_status() # Lädt den Bot-Status in g g.bot_running = bot_status() # Lädt den Bot-Status in g
# Hole die Liste der Gilden aus der Datenbank # Lade die Gilden des Nutzers aus der Session (ohne DB-Zugriff)
connection = get_db_connection()
cursor = connection.cursor(dictionary=True)
# Lade die Gilden des Nutzers
user_guilds = session.get("discord_guilds", []) user_guilds = session.get("discord_guilds", [])
user_guild_ids = [guild["id"] for guild in user_guilds]
# Nur DB-Zugriff wenn Gilden-Daten nicht im Cache sind
# Finde nur die Gilden, die auch in der Datenbank existieren guild_cache_key = f"guild_cache_{g.user_info['id']}"
cursor.execute("SELECT guild_id FROM guilds WHERE guild_id IN (%s)" % ','.join(['%s'] * len(user_guild_ids)), user_guild_ids) if guild_cache_key not in session or not session[guild_cache_key]:
existing_guilds = cursor.fetchall() try:
with get_db_cursor() as (cursor, connection):
# Filtere die Gilden des Nutzers basierend auf der Existenz in der Datenbank user_guild_ids = [guild["id"] for guild in user_guilds]
g.guilds = [guild for guild in user_guilds if int(guild["id"]) in {g["guild_id"] for g in existing_guilds}]
if user_guild_ids: # Nur wenn Gilden existieren
cursor.close() # Finde nur die Gilden, die auch in der Datenbank existieren
connection.close() placeholders = ','.join(['%s'] * len(user_guild_ids))
cursor.execute(f"SELECT guild_id FROM guilds WHERE guild_id IN ({placeholders})", user_guild_ids)
existing_guilds = cursor.fetchall()
existing_guild_ids = {g["guild_id"] for g in existing_guilds}
# Filtere die Gilden des Nutzers basierend auf der Existenz in der Datenbank
filtered_guilds = [guild for guild in user_guilds if int(guild["id"]) in existing_guild_ids]
# Cache die gefilterten Gilden für 5 Minuten
session[guild_cache_key] = filtered_guilds
session[f"{guild_cache_key}_time"] = time.time()
g.guilds = filtered_guilds
else:
g.guilds = []
except Exception as e:
print(f"Error loading guild data: {e}")
# Fallback: Verwende alle Gilden aus der Session
g.guilds = user_guilds
# Setze einen Flag für DB-Probleme
g.db_error = True
else:
# Prüfe Cache-Alter (5 Minuten TTL)
cache_time = session.get(f"{guild_cache_key}_time", 0)
if time.time() - cache_time > 300: # 5 Minuten
# Cache ist abgelaufen, lösche ihn
session.pop(guild_cache_key, None)
session.pop(f"{guild_cache_key}_time", None)
g.guilds = user_guilds # Fallback
else:
# Verwende gecachte Daten
g.guilds = session[guild_cache_key]
else: else:
# Falls der Benutzer nicht eingeloggt ist, keine Daten setzen # Falls der Benutzer nicht eingeloggt ist, keine Daten setzen
g.user_info = None g.user_info = None
g.is_admin = False g.is_admin = False
g.guilds = [] g.guilds = []
g.bot_running = False g.bot_running = False
g.db_error = False
@app.route("/callback") @app.route("/callback")
def callback(): def callback():

2
bot.py
View File

@@ -196,7 +196,7 @@ def retry_query(func, *args, retries=3, delay=5):
pool = mysql.connector.pooling.MySQLConnectionPool( pool = mysql.connector.pooling.MySQLConnectionPool(
pool_name="mypool", pool_name="mypool",
pool_size=25, # Reduziert von 30 auf 25 (App: 15, Bot: 25 = 40 total) pool_size=15, # Weiter reduziert von 25 auf 15 (App: 8, Bot: 15 = 23 total)
pool_reset_session=True, pool_reset_session=True,
autocommit=True, autocommit=True,
host=DB_HOST, host=DB_HOST,