Un pipeline de CI puede tardar varios minutos y aun así terminar con un mensaje poco útil: “no llegó el correo”. En una prueba que usa un disposable email address, ese fallo no dice si la aplicación no publicó el evento, si el worker quedó pendiente, si Kubernetes reinició el pod o si el inbox todavía no había recibido el mensaje.
La solución práctica es asignar un presupuesto de tiempo a cada frontera. No se trata de hacer el test más rápido a la fuerza. Se trata de saber qué parte consumió el tiempo disponible para que el siguiente incidente sea menos misterioso.
El síntoma: un timeout que no explica nada
Imagina una prueba de registro en un namespace de staging. El formulario responde 201, pero el test espera el mensaje de confirmación durante 60 segundos y falla. El equipo revisa el log del navegador, ve un “email not found” y vuelve a lanzar el job. A veces pasa; otras no.
Ese retry es tentador, pero mezcla varios relojes:
- la publicación del evento por la API;
- la recogida del evento por el worker;
- el envío al proveedor de correo;
- la aparición del mensaje en el buzón de prueba;
- la lectura del mensaje y la confirmación del enlace.
Cuando todos viven bajo un único timeout, la prueba pierde su capacidad de diagnóstico. Un SRE necesita al menos una señal por frontera, aunque sea una señal sencilla.
Define un presupuesto por etapa
Empieza con una tabla que pueda leer cualquier persona del equipo. Por ejemplo, para un flujo normal de 45 segundos:
| Etapa | Presupuesto | Evidencia mínima |
|---|---|---|
| API publica el evento | 2 s |
request_id y estado HTTP |
| Worker recoge el evento | 8 s | nombre del pod y contador |
| Proveedor acepta el envío | 10 s |
message_id o error |
| Mensaje aparece en el inbox | 20 s |
mailbox_id y received_at
|
| Test lee y verifica | 5 s | estado final y código de salida |
Los números no son universales. Son un contrato inicial que luego se ajusta con datos reales. Si la mayoría de las entregas ocurre en cinco segundos, un presupuesto de veinte quizá sea razonable para CI; si la cola tarda más por la noche, hay que medirlo y no adivinarlo.
La prueba debe conservar los tiempos de cada etapa. No guardes el contenido completo del mensaje en un artefacto público: normalmente basta con un identificador, un hash de dirección y los estados. Así el diagnóstico ayuda sin filtrar datos de prueba.
Qué observar en Kubernetes
En Kubernetes, un fallo de correo puede estar oculto detrás de una ejecución aparentemente sana. Revisa cuatro señales antes de aumentar el timeout:
-
Reinicios del worker. Un
restartCountnuevo cerca del momento del envío puede explicar una cola que no avanzó. - Edad del pod. Si el despliegue rotó durante la prueba, el evento quizá quedó en memoria y no llegó a ser confirmado.
- Profundidad de la cola. Una cola creciendo con consumidores listos indica presión; una cola quieta con cero consumidores indica otro problema.
-
Correlación. El mismo
request_iddebe aparecer en la API, el worker y el adaptador de correo.
Para una consulta rápida, un job de diagnóstico puede producir algo como esto:
run=ci-1842 request=req-7f2 worker=mail-worker-6d8c
api=accepted worker=processed provider=accepted inbox=pending
pod_restarts=0 queue_depth=3 elapsed=18s
Ese estado “inbox=pending” es mucho más útil que un timeout genérico. Si la cola sigue creciendo, el test no debe culpar al buzón todavía.
Una implementación sencilla en CI
Usa un reloj monotónico y registra una línea al entrar y salir de cada etapa. El adaptador del buzón debería aceptar un deadline absoluto, no reiniciar el contador completo en cada poll. De lo contrario, diez intentos de seis segundos pueden convertir un presupuesto de veinte segundos en un minuto sin que sea evidente.
También conviene reservar una dirección por ejecución. Un buzón compartido hace difícil saber si el mensaje actual llegó o si el test leyó un correo viejo. En documentación y búsquedas internas pueden aparecer errores como tempail o tamp mail com; no los uses para diseñar la lógica, pero sí puedes mapearlos a la terminología correcta en el buscador del equipo.
Cuando el mensaje no llega, conserva el resumen de estados y termina con una causa concreta: worker-timeout, provider-rejected, inbox-timeout o verification-timeout. Así un retry puede ser selectivo y no repetir toda la suite sin motivo.
Para sistemas con varios consumidores, merece la pena formalizar el contrato de señales. El artículo sobre contratos de correo para automatizaciones muestra una forma de pensar en eventos y estados sin depender de un log enorme. Y para las alertas operativas, las alertas de failover comprobables siguen la misma idea: una alerta debe poder probarse con una evidencia observable.
Checklist para el siguiente incidente
- ¿Cada etapa tiene un presupuesto separado?
- ¿La prueba conserva
request_id,mailbox_idymessage_idsin guardar datos innecesarios? - ¿El worker tuvo reinicios o perdió el lease del evento?
- ¿La cola avanzaba, estaba bloqueada o no tenía consumidores?
- ¿El deadline era absoluto o se reiniciaba en cada intento?
- ¿El resultado final distingue entrega, lectura y verificación?
Un timeout sigue siendo una limitación real, pero deja de ser una explicación vacía. Con presupuestos pequeños, señales correlacionadas y un buzón aislado por ejecución, Kubernetes y CI pueden decirte dónde está el problema antes de que alguien pulse “reintentar”.
Top comments (0)