fix: Añadir reintentos de conexión MySQL y limitar reinicios de servicios

- get_connection() reintenta hasta 30 veces con delays de 2s
- iniciar_todo.py limita reinicios a 3 por servicio con cooldown de 60s
- Evitar loops infinitos cuando MySQL no está disponible
This commit is contained in:
2026-03-20 03:55:22 -06:00
parent baaf4bc1f7
commit ae51b6333c
2 changed files with 72 additions and 31 deletions

View File

@@ -1,10 +1,13 @@
import sqlite3 import sqlite3
import mysql.connector import mysql.connector
import json import json
import time
from mysql.connector import Error as MySQLError from mysql.connector import Error as MySQLError
from botdiscord.config import get_db_config, get_db_type from botdiscord.config import get_db_config, get_db_type
_connection = None _connection = None
MAX_CONNECTION_RETRIES = 30
CONNECTION_RETRY_DELAY = 2
def get_connection(): def get_connection():
global _connection global _connection
@@ -13,39 +16,53 @@ def get_connection():
if db_type == "mysql": if db_type == "mysql":
db_config = get_db_config() db_config = get_db_config()
# Si no hay conexión o no está activa, intentamos conectar/reconectar
if _connection is None: if _connection is None:
try: for attempt in range(1, MAX_CONNECTION_RETRIES + 1):
_connection = mysql.connector.connect( try:
host=db_config.get("host"), _connection = mysql.connector.connect(
port=db_config.get("port"), host=db_config.get("host"),
user=db_config.get("user"), port=db_config.get("port"),
password=db_config.get("password"), user=db_config.get("user"),
database=db_config.get("name"), password=db_config.get("password"),
consume_results=True, database=db_config.get("name"),
connection_timeout=5 consume_results=True,
) connection_timeout=10
except MySQLError as e: )
print(f"CRITICAL: Could not establish initial MySQL connection: {e}") print(f"[DB] MySQL conectado exitosamente")
raise break
except MySQLError as e:
if attempt < MAX_CONNECTION_RETRIES:
print(f"[DB] Intento {attempt}/{MAX_CONNECTION_RETRIES}: MySQL no disponible, reintentando en {CONNECTION_RETRY_DELAY}s...")
time.sleep(CONNECTION_RETRY_DELAY)
_connection = None
else:
print(f"[DB] CRITICAL: No se pudo conectar a MySQL después de {MAX_CONNECTION_RETRIES} intentos")
raise
# Verificar salud de la conexión existente
try: try:
_connection.ping(reconnect=True, attempts=3, delay=1) _connection.ping(reconnect=True, attempts=3, delay=1)
except MySQLError: except MySQLError:
try: for attempt in range(1, 6):
_connection = mysql.connector.connect( try:
host=db_config.get("host"), print(f"[DB] Reconectando a MySQL (intento {attempt}/5)...")
port=db_config.get("port"), _connection = mysql.connector.connect(
user=db_config.get("user"), host=db_config.get("host"),
password=db_config.get("password"), port=db_config.get("port"),
database=db_config.get("name"), user=db_config.get("user"),
consume_results=True, password=db_config.get("password"),
connection_timeout=5 database=db_config.get("name"),
) consume_results=True,
except MySQLError as e: connection_timeout=10
print(f"CRITICAL: MySQL reconnection failed: {e}") )
raise print(f"[DB] MySQL reconectado exitosamente")
break
except MySQLError as e:
if attempt < 5:
time.sleep(2)
_connection = None
else:
print(f"[DB] CRITICAL: MySQL reconnection failed: {e}")
raise
return _connection return _connection
else: else:

View File

@@ -25,6 +25,9 @@ print("🤖 Iniciando Bots de Traducción...")
print("=" * 40) print("=" * 40)
processes = [] processes = []
restart_counts = {}
MAX_RESTARTS = 3
RESTART_COOLDOWN = 60
def start_process(cmd, name, delay_before=0): def start_process(cmd, name, delay_before=0):
if delay_before > 0: if delay_before > 0:
@@ -72,11 +75,32 @@ signal.signal(signal.SIGTERM, signal_handler)
while True: while True:
for p, name in processes: for p, name in processes:
if p.poll() is not None: if p.poll() is not None:
log(f"⚠️ {name} se detuvo, reiniciando...") if name not in restart_counts:
restart_counts[name] = {"count": 0, "last_restart": 0}
current_time = time.time()
if current_time - restart_counts[name]["last_restart"] > RESTART_COOLDOWN:
restart_counts[name]["count"] = 0
restart_counts[name]["count"] += 1
restart_counts[name]["last_restart"] = current_time
if restart_counts[name]["count"] > MAX_RESTARTS:
log(f"{name} se detuvo {restart_counts[name]['count']} veces. Demasiados reinicios. Esperando {RESTART_COOLDOWN}s...")
time.sleep(RESTART_COOLDOWN)
restart_counts[name]["count"] = 0
continue
log(f"⚠️ {name} se detuvo (intento {restart_counts[name]['count']}/{MAX_RESTARTS}), reiniciando...")
delay = 5 if name != "Discord Bot" else 10
if name == "Discord Bot": if name == "Discord Bot":
p1 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "botdiscord/bot.py"], "Discord Bot", delay_before=10) p1 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "botdiscord/bot.py"], "Discord Bot", delay_before=delay)
elif name == "Telegram Bot": elif name == "Telegram Bot":
p2 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "bottelegram/telegram_bot.py"], "Telegram Bot", delay_before=5) p2 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "bottelegram/telegram_bot.py"], "Telegram Bot", delay_before=delay)
elif name == "Panel Web": elif name == "Panel Web":
p3 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "panel/main.py"], "Panel Web", delay_before=0) p3 = start_process(["python3", "-X", "faulthandler", "-X", "importsys", "panel/main.py"], "Panel Web", delay_before=0)
time.sleep(5) time.sleep(5)