El Asesino Silencioso: ¿Cómo puede un Django Signal hacer que tu plataforma de soporte de IA se bloquee?
Has estado programando durante horas. La funcionalidad es elegante, las pruebas pasan, la revisión de código parece perfecta y presionas merge. Cuarenta y cinco minutos después, Slack explota con alertas rojas, quejas de clientes y el CEO preguntando que sucede. Tus agentes IA de soporte, los que los clientes aman, se quedan congelados. Conversaciones atascadas. ChromaDB con timeouts. Base de datos saturada. Todo lo que construiste colapsa en tiempo real. Al final, se rastrea el origen a tres líneas inocentes de código añadidas un martes por la mañana.
Resumen rápido: una llamada a save dentro de un signal de Django provocó escrituras recursivas, disparó signals relacionados, saturó la base de datos, bloqueó workers de Celery y provocó un fallo total bajo carga. La regla que aprendimos es sencilla y contundente: los signals no deben modificar modelos; solo deben encolar trabajo asíncrono después de confirmar la transacción.
Contexto del problema: el flujo era simple. Usuarios envían preguntas. Agentes IA basados en LangGraph y modelos externos responden. Mensajes se almacenan y se generan embeddings para ChromaDB con búsqueda semántica. Los modelos eran típicos: soporteConversación y MensajeConversación enlazado por clave foránea. En un cambio aparentemente inocuo se añadió un handler que al detectar un mensaje de rol assistant en post save encolaba una tarea a Celery para generar embeddings y además llamaba a conversation.save. Esa última llamada parecía inofensiva en local y en staging, pero bajo una campaña promocional real disparó un bucle exponencial de escrituras y signals.
La secuencia de fallo bajo pico de carga fue la siguiente: varios cientos de sesiones nuevas simultáneas, cada respuesta del asistente inserta un MensajeConversación, el post save dispara una tarea y a la vez guarda el objeto conversación en la base de datos, ese save del padre dispara otros signals y más escrituras, y así sucesivamente. En minutos el pool de conexiones de base de datos se agota, los workers de Celery quedan bloqueados esperando I O, ChromaDB se atrasa por las colas de la base de datos y la plataforma se queda inmovilizada. El tiempo de recuperación superó las cuatro horas.
Por qué sucede: guardar modelos desde un signal genera saves anidados que reactivan signals en cascada. Bajo concurrencia esto se convierte en un ataque accidental contra tu propia infraestructura porque las operaciones de escritura se multiplican exponencialmente.
Las cuatro medidas que nos salvaron y que recomendamos implementar inmediatamente son las siguientes.
1. Proteger siempre con la bandera created y usar on commit. El handler de post save debe actuar solo cuando el registro es nuevo y encolar la tarea asíncrona solo después de que la transacción haya sido confirmada. Así se evita que saves intermedios dentro del mismo flujo vuelvan a disparar handlers y se mantiene la separación de responsabilidades entre escritura y procesamiento asíncrono.
2. Hacer que Celery actualice los modelos de forma segura. Cuando la tarea asíncrona almacene resultados como embedding id o flags de procesamiento, usar operaciones de QuerySet que actualizan en bloque con update para evitar disparar signals. Además emplear update fields cuando sea necesario para minimizar triggers. Con esto Celery puede modificar el estado sin reactivar handlers y sin provocar bucles.
3. Actualizar estadísticas del padre con QuerySet update en lugar de guardar el objeto. No hacer conversation.message count = n y conversation.save desde un signal. En su lugar ejecutar SupportConversation.objects.filter(id = x).update(message count = nuevo valor). Las operaciones de QuerySet evitan signals, son atómicas y mucho más eficientes.
4. Agrupar actualizaciones en lugar de hacerlas por mensaje. En vez de recalcular y guardar métricas por cada mensaje, programar una tarea periódica que cada N segundos o minutos agregue y actualice en batch todos los conteos y métricas. Con 500 mensajes concurrentes resulta inmensamente más eficiente procesar 1 batch cada 30 segundos que 500 updates individuales.
Probar y monitorear para detectar cascadas de signals es crítico. Implementa tests que verifiquen que crear un mensaje genera exactamente una escritura y que bajo una carga simulada no se superan umbrales razonables de updates. Monitorea profundidad y frecuencia de signals en producción y configura alertas cuando las escrituras por petición aumenten inesperadamente.
Checklist de buenas prácticas que aplicamos en Q2BSTUDIO y recomendamos a nuestros clientes: usar siempre la bandera created en handlers, emplear transaction on commit para encolar trabajo asíncrono, mantener los signals puros y nunca modificar modelos desde ellos, usar queryset update en lugar de save en handlers, usar update fields cuando Celery actualiza modelos, agrupar tareas costosas en lotes, someter el sistema a pruebas de estrés con carga concurrente y monitorizar la profundidad de los signals en producción.
En Q2BSTUDIO somos especialistas en desarrollo de aplicaciones a medida y software a medida y comprendemos que la fiabilidad a escala requiere tanto arquitectura como disciplina en patrones de integración. Si tu plataforma utiliza agentes IA para empresas, embeddings o bases de vectores, podemos ayudarte a diseñar pipelines robustos que eviten estos fallos silenciosos. Con experiencia en servicios de inteligencia artificial, servicios cloud AWS y Azure y prácticas de ciberseguridad, Q2BSTUDIO integra soluciones que incluyen automatización segura, orquestación de tareas con Celery y despliegues que escalan sin colapsar la base de datos.
Además ofrecemos servicios de servicios inteligencia de negocio y power bi para convertir logs y métricas en dashboards accionables que muestran cuándo una señal empieza a comportarse de forma anómala. Nuestro enfoque combina ingeniería backend robusta, políticas de seguridad y pruebas de estrés para minimizar riesgos de producción.
Reglas finales y lección aprendida: los signals son útiles pero son minas escondidas. Evita llamar a save dentro de handlers. Encola tareas asíncronas después del commit. Deja que Celery haga las actualizaciones de estado con operaciones que no disparen signals. Siguiendo estas reglas reducirás la probabilidad de provocar una tormenta de escrituras que golpee tus bases de datos, congele workers y detenga tus agentes IA justo cuando más los necesitan tus clientes.
¿Quieres que revisemos tu arquitectura de señales y colas para evitar este tipo de fallos? En Q2BSTUDIO diseñamos soluciones a la medida que combinan inteligencia artificial, ciberseguridad, servicios cloud y analítica de negocio para que tus agentes IA funcionen con fiabilidad a cualquier escala.
Palabras clave integradas: aplicaciones a medida, software a medida, inteligencia artificial, ciberseguridad, servicios cloud aws y azure, servicios inteligencia de negocio, ia para empresas, agentes IA, power bi.
Comentarios