error fixing

This commit is contained in:
2026-03-22 12:42:47 -06:00
parent a74c28b63e
commit 76c2f33ea6
4 changed files with 167 additions and 68 deletions

View File

@@ -52,10 +52,12 @@ class ReportConsumer:
except Exception as e: except Exception as e:
logger.error(f"Error processing report message: {e}", exc_info=True) logger.error(f"Error processing report message: {e}", exc_info=True)
# Rollback explícito en caso de error
self.user_repo.db.rollback()
raise raise
def _handle_create_report(self, message: ReportMessage): def _handle_create_report(self, message: ReportMessage):
"""Handle report create event""" """Handle report create event con manejo de transacciones cruzadas"""
try: try:
logger.info(f"Creating report: {message.id_reporte} from user {message.id_usuario}") logger.info(f"Creating report: {message.id_reporte} from user {message.id_usuario}")
@@ -73,20 +75,33 @@ class ReportConsumer:
fecha_creacion=fecha_creacion fecha_creacion=fecha_creacion
) )
# Save to repository try:
saved_report = self.repo.save(report) # Save to MongoDB repository
logger.info(f"Report created successfully: {message.id_reporte}") saved_report = self.repo.save(report)
logger.info(f"Report created successfully in MongoDB: {message.id_reporte}")
except Exception as mongo_error:
logger.error(f"Error saving report to MongoDB: {mongo_error}", exc_info=True)
raise
# Increment user's report counter try:
self.user_repo.increment_reports(message.id_usuario) # Increment user's report counter in MySQL
logger.info(f"Incremented report counter for user: {message.id_usuario}") self.user_repo.increment_reports(message.id_usuario)
logger.info(f"Incremented report counter for user: {message.id_usuario}")
except Exception as sql_error:
logger.error(f"Error incrementing report counter: {sql_error}", exc_info=True)
# Rollback SQL transaction
self.user_repo.db.rollback()
# Note: MongoDB save cannot be rolled back, log for manual cleanup
logger.critical(f"INCONSISTENCY: Report {message.id_reporte} saved to MongoDB but user counter not incremented for user {message.id_usuario}")
raise
except Exception as e: except Exception as e:
logger.error(f"Error creating report: {e}", exc_info=True) logger.error(f"Error creating report: {e}", exc_info=True)
self.user_repo.db.rollback()
raise raise
def _handle_update_visibility(self, message: ReportMessage): def _handle_update_visibility(self, message: ReportMessage):
"""Handle report visibility update event""" """Handle report visibility update event con manejo de transacciones"""
try: try:
logger.info(f"Updating visibility for report: {message.id_reporte}") logger.info(f"Updating visibility for report: {message.id_reporte}")
@@ -96,9 +111,13 @@ class ReportConsumer:
logger.warning(f"Report not found: {message.id_reporte}") logger.warning(f"Report not found: {message.id_reporte}")
return return
# Update visibility # Update visibility in MongoDB
self.repo.update_visibility(message.id_reporte, message.visibilidad) try:
logger.info(f"Report visibility updated: {message.id_reporte} -> {message.visibilidad}") self.repo.update_visibility(message.id_reporte, message.visibilidad)
logger.info(f"Report visibility updated: {message.id_reporte} -> {message.visibilidad}")
except Exception as mongo_error:
logger.error(f"Error updating report visibility in MongoDB: {mongo_error}", exc_info=True)
raise
# Penalize author if visibility is very low (shadowban) # Penalize author if visibility is very low (shadowban)
if message.penalize_author and message.visibilidad < 20: if message.penalize_author and message.visibilidad < 20:
@@ -109,11 +128,17 @@ class ReportConsumer:
new_rating = max(0, user.calificacion - 5) new_rating = max(0, user.calificacion - 5)
self.user_repo.update_rating(report.id_usuario, new_rating) self.user_repo.update_rating(report.id_usuario, new_rating)
logger.info(f"Author penalized: user {report.id_usuario} rating reduced to {new_rating}") logger.info(f"Author penalized: user {report.id_usuario} rating reduced to {new_rating}")
except Exception as e: else:
logger.error(f"Error penalizing author: {e}") logger.warning(f"User not found for penalty: {report.id_usuario}")
except Exception as penalty_error:
logger.error(f"Error penalizing author: {penalty_error}", exc_info=True)
self.user_repo.db.rollback()
logger.critical(f"INCONSISTENCY: Report {message.id_reporte} visibility updated but author penalty failed")
raise
except Exception as e: except Exception as e:
logger.error(f"Error updating report visibility: {e}", exc_info=True) logger.error(f"Error updating report visibility: {e}", exc_info=True)
self.user_repo.db.rollback()
raise raise
def _handle_delete_report(self, message: ReportMessage): def _handle_delete_report(self, message: ReportMessage):
@@ -129,6 +154,7 @@ class ReportConsumer:
except Exception as e: except Exception as e:
logger.error(f"Error deleting report: {e}", exc_info=True) logger.error(f"Error deleting report: {e}", exc_info=True)
self.user_repo.db.rollback()
raise raise
def start(self): def start(self):
@@ -142,6 +168,13 @@ class ReportConsumer:
except Exception as e: except Exception as e:
logger.error(f"Consumer error: {e}", exc_info=True) logger.error(f"Consumer error: {e}", exc_info=True)
raise raise
finally:
# Asegurar cierre de sesión SQL
if self.user_repo.db:
try:
self.user_repo.db.close()
except Exception as e:
logger.error(f"Error closing database session: {e}")
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -50,6 +50,8 @@ class UserConsumer:
except Exception as e: except Exception as e:
logger.error(f"Error processing user message: {e}", exc_info=True) logger.error(f"Error processing user message: {e}", exc_info=True)
# Rollback en caso de error en el procesamiento del mensaje
self.repo.db.rollback()
raise raise
def _handle_create_user(self, message: UserMessage): def _handle_create_user(self, message: UserMessage):
@@ -75,12 +77,13 @@ class UserConsumer:
biografia=message.biografia biografia=message.biografia
) )
# Save to repository # Save to repository with transaction handling
saved_user = self.repo.save(user) saved_user = self.repo.save(user)
logger.info(f"User created successfully: {saved_user.user_id} - {saved_user.email}") logger.info(f"User created successfully: {saved_user.user_id} - {saved_user.email}")
except Exception as e: except Exception as e:
logger.error(f"Error creating user: {e}", exc_info=True) logger.error(f"Error creating user: {e}", exc_info=True)
self.repo.db.rollback()
raise raise
def _handle_update_user(self, message: UserMessage): def _handle_update_user(self, message: UserMessage):
@@ -104,12 +107,13 @@ class UserConsumer:
if message.biografia is not None: if message.biografia is not None:
user.biografia = message.biografia user.biografia = message.biografia
# Save to repository # Save to repository with transaction handling
updated_user = self.repo.update(user) updated_user = self.repo.update(user)
logger.info(f"User updated successfully: {message.user_id}") logger.info(f"User updated successfully: {message.user_id}")
except Exception as e: except Exception as e:
logger.error(f"Error updating user: {e}", exc_info=True) logger.error(f"Error updating user: {e}", exc_info=True)
self.repo.db.rollback()
raise raise
def _handle_delete_user(self, message: UserMessage): def _handle_delete_user(self, message: UserMessage):
@@ -125,6 +129,7 @@ class UserConsumer:
except Exception as e: except Exception as e:
logger.error(f"Error deleting user: {e}", exc_info=True) logger.error(f"Error deleting user: {e}", exc_info=True)
self.repo.db.rollback()
raise raise
def start(self): def start(self):
@@ -138,6 +143,13 @@ class UserConsumer:
except Exception as e: except Exception as e:
logger.error(f"Consumer error: {e}", exc_info=True) logger.error(f"Consumer error: {e}", exc_info=True)
raise raise
finally:
# Asegurar cierre de sesión
if self.repo.db:
try:
self.repo.db.close()
except Exception as e:
logger.error(f"Error closing database session: {e}")
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -14,9 +14,13 @@ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base() Base = declarative_base()
def get_db(): def get_db():
"""Obtiene una sesión de base de datos""" """Obtiene una sesión de base de datos con manejo de rollback"""
db = SessionLocal() db = SessionLocal()
try: try:
yield db yield db
db.commit() # Commit explícito si no hubo errores
except Exception as e:
db.rollback() # Rollback si ocurre cualquier error
raise e
finally: finally:
db.close() db.close() # Siempre cerrar la sesión

View File

@@ -3,6 +3,9 @@ from domain.users import User
from infrastructure.adapters.persistence.models import UserModel from infrastructure.adapters.persistence.models import UserModel
from infrastructure.adapters.persistence.db import SessionLocal from infrastructure.adapters.persistence.db import SessionLocal
from typing import List, Optional from typing import List, Optional
import logging
logger = logging.getLogger(__name__)
class UserRepositorySQL(UserRepository): class UserRepositorySQL(UserRepository):
"""Implementación del repositorio de Usuarios usando SQLAlchemy (MySQL)""" """Implementación del repositorio de Usuarios usando SQLAlchemy (MySQL)"""
@@ -11,48 +14,68 @@ class UserRepositorySQL(UserRepository):
self.db = db_session or SessionLocal() self.db = db_session or SessionLocal()
def save(self, user: User) -> User: def save(self, user: User) -> User:
"""Guarda un nuevo usuario""" """Guarda un nuevo usuario con manejo de transacciones"""
db_user = UserModel( try:
nombre=user.nombre, db_user = UserModel(
apellido=user.apellido, nombre=user.nombre,
email=user.email, apellido=user.apellido,
fecha_nacimiento=user.fecha_nacimiento, email=user.email,
fecha_creacion=user.fecha_creacion, fecha_nacimiento=user.fecha_nacimiento,
calificacion=user.calificacion, fecha_creacion=user.fecha_creacion,
numero_reportes=user.numero_reportes, calificacion=user.calificacion,
url_foto_perfil=user.url_foto_perfil, numero_reportes=user.numero_reportes,
biografia=user.biografia url_foto_perfil=user.url_foto_perfil,
) biografia=user.biografia
self.db.add(db_user) )
self.db.commit() self.db.add(db_user)
self.db.refresh(db_user) self.db.commit()
self.db.refresh(db_user)
# Convertir de vuelta a dominio logger.info(f"Usuario guardado exitosamente: {db_user.user_id}")
return self._to_domain(db_user) return self._to_domain(db_user)
except Exception as e:
self.db.rollback()
logger.error(f"Error al guardar usuario: {e}", exc_info=True)
raise
def find_by_id(self, user_id: int) -> Optional[User]: def find_by_id(self, user_id: int) -> Optional[User]:
"""Obtiene un usuario por ID""" """Obtiene un usuario por ID"""
db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
return self._to_domain(db_user) if db_user:
return None return self._to_domain(db_user)
return None
except Exception as e:
logger.error(f"Error al buscar usuario por ID {user_id}: {e}", exc_info=True)
raise
def find_by_email(self, email: str) -> Optional[User]: def find_by_email(self, email: str) -> Optional[User]:
"""Obtiene un usuario por email""" """Obtiene un usuario por email"""
db_user = self.db.query(UserModel).filter(UserModel.email == email).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.email == email).first()
return self._to_domain(db_user) if db_user:
return None return self._to_domain(db_user)
return None
except Exception as e:
logger.error(f"Error al buscar usuario por email {email}: {e}", exc_info=True)
raise
def find_all(self) -> List[User]: def find_all(self) -> List[User]:
"""Obtiene todos los usuarios""" """Obtiene todos los usuarios"""
db_users = self.db.query(UserModel).all() try:
return [self._to_domain(user) for user in db_users] db_users = self.db.query(UserModel).all()
return [self._to_domain(user) for user in db_users]
except Exception as e:
logger.error(f"Error al obtener todos los usuarios: {e}", exc_info=True)
raise
def update(self, user: User) -> User: def update(self, user: User) -> User:
"""Actualiza un usuario""" """Actualiza un usuario con manejo de transacciones"""
db_user = self.db.query(UserModel).filter(UserModel.user_id == user.user_id).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.user_id == user.user_id).first()
if not db_user:
logger.warning(f"Usuario no encontrado para actualizar: {user.user_id}")
return user
db_user.nombre = user.nombre db_user.nombre = user.nombre
db_user.apellido = user.apellido db_user.apellido = user.apellido
db_user.calificacion = user.calificacion db_user.calificacion = user.calificacion
@@ -61,32 +84,59 @@ class UserRepositorySQL(UserRepository):
db_user.biografia = user.biografia db_user.biografia = user.biografia
self.db.commit() self.db.commit()
self.db.refresh(db_user) self.db.refresh(db_user)
logger.info(f"Usuario actualizado exitosamente: {user.user_id}")
return self._to_domain(db_user) return self._to_domain(db_user)
return user except Exception as e:
self.db.rollback()
logger.error(f"Error al actualizar usuario {user.user_id}: {e}", exc_info=True)
raise
def delete(self, user_id: int) -> bool: def delete(self, user_id: int) -> bool:
"""Elimina un usuario""" """Elimina un usuario con manejo de transacciones"""
db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
self.db.delete(db_user) if db_user:
self.db.commit() self.db.delete(db_user)
return True self.db.commit()
return False logger.info(f"Usuario eliminado exitosamente: {user_id}")
return True
logger.warning(f"Usuario no encontrado para eliminar: {user_id}")
return False
except Exception as e:
self.db.rollback()
logger.error(f"Error al eliminar usuario {user_id}: {e}", exc_info=True)
raise
def increment_reports(self, user_id: int) -> None: def increment_reports(self, user_id: int) -> None:
"""Incrementa el contador de reportes de un usuario""" """Incrementa el contador de reportes con manejo de transacciones"""
db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
db_user.numero_reportes += 1 if db_user:
self.db.commit() db_user.numero_reportes += 1
self.db.commit()
logger.info(f"Contador de reportes incrementado para usuario: {user_id}")
else:
logger.warning(f"Usuario no encontrado para incrementar reportes: {user_id}")
except Exception as e:
self.db.rollback()
logger.error(f"Error al incrementar reportes del usuario {user_id}: {e}", exc_info=True)
raise
def update_rating(self, user_id: int, new_rating: float) -> None: def update_rating(self, user_id: int, new_rating: float) -> None:
"""Actualiza la calificación de un usuario""" """Actualiza la calificación de un usuario con manejo de transacciones"""
db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first() try:
if db_user: db_user = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
# Asegurar que la calificación esté en el rango 0-100 if db_user:
db_user.calificacion = max(0, min(100, new_rating)) # Asegurar que la calificación esté en el rango 0-100
self.db.commit() db_user.calificacion = max(0, min(100, new_rating))
self.db.commit()
logger.info(f"Calificación actualizada para usuario {user_id}: {db_user.calificacion}")
else:
logger.warning(f"Usuario no encontrado para actualizar calificación: {user_id}")
except Exception as e:
self.db.rollback()
logger.error(f"Error al actualizar calificación del usuario {user_id}: {e}", exc_info=True)
raise
def _to_domain(self, db_user: UserModel) -> User: def _to_domain(self, db_user: UserModel) -> User:
"""Convierte un modelo SQLAlchemy a un objeto de dominio""" """Convierte un modelo SQLAlchemy a un objeto de dominio"""