En Kubernetes, una alerta de email lenta se parece demasiado a un fallo completo. El pod de la aplicación termina correctamente, el proveedor SMTP responde, pero el mensaje de verificación tarda dos minutos en llegar. Para la persona que está probando el flujo, la experiencia es la misma: pulsa «reenviar» y acaba creando varios intentos.
En una guardia aprendí a no empezar cambiando timeouts. Primero hay que separar tres tiempos: el que tarda la aplicación en aceptar el evento, el que tarda el proveedor en aceptar el mensaje y el que tarda el mensaje en aparecer en el buzón de prueba. Esa separación convierte un síntoma difuso en una investigación de SRE que se puede repetir.
El síntoma no siempre es un fallo de SMTP
La métrica email_verification_failed suele mezclar errores muy distintos. Un 5xx inmediato del proveedor no tiene el mismo significado que un 202 Accepted seguido de una entrega lenta. Tampoco es igual que el worker haya perdido el lease antes de publicar el mensaje.
Conviene registrar un identificador de intento y cuatro marcas de tiempo:
attempt_created_at
provider_accepted_at
message_observed_at
attempt_finished_at
No guardaría el asunto completo ni la dirección real en logs de producción. Para una prueba sintética basta con un identificador hasheado, el nombre del entorno y el resultado. El objetivo es observar la ruta, no coleccionar datos que luego nadie revisa.
Si el proveedor acepta en 300 ms pero message_observed_at llega 90 segundos después, el problema probablemente está en la entrega, el buzón o la forma de consultar. Si la aceptación ya tarda 20 segundos, hay que mirar la cola del worker, la resolución DNS, la conexión saliente y los límites del proveedor.
Para profundizar en una investigación parecida, resulta útil aislar fallos de email en Kubernetes antes de tocar la configuración del despliegue.
Qué evidencia recoger primero
Antes de reiniciar pods, captura una pequeña fotografía del incidente:
- Versión y entorno: namespace, imagen desplegada y configuración efectiva (sin secretos).
- Ruta del evento: nombre del worker, cola, proveedor y código de respuesta.
- Latencias separadas: aplicación, aceptación SMTP y aparición del mensaje.
- Tamaño de la cola: edad del mensaje más antiguo y número de reintentos.
- Ventana temporal: cuándo empezó y si coincide con un cambio o una saturación.
Un error frecuente es mirar solamente los logs del pod que envía. Eso deja fuera los mensajes que sí fueron aceptados pero nunca fueron visibles para la prueba. Tambien he visto dashboards que muestran la media; la media se ve bien aunque un porcentaje pequeño de usuarios espere demasiado. Usa p95 y p99 cuando la experiencia dependa de un enlace con caducidad.
La comprobación sintética debe publicar un mensaje con una dirección de prueba aislada y consultar con una frecuencia limitada. Un generador de correo desechable puede servir para crear datos efímeros en un entorno de QA, pero no debe convertirse en almacenamiento permanente ni en una dependencia oculta del camino crítico. En otro caso, un generador de correo temporal es útil para verificar la entrega sin reutilizar una bandeja personal.
Un runbook en cuatro pasos
1. Confirma si el evento salió de Kubernetes
Busca el attempt_id en el worker y en la cola. Si no existe una aceptación del proveedor, el fallo está antes o durante la salida. Revisa el ServiceAccount, las políticas de red y el límite de conexiones, pero evita hacer tres cambios a la vez.
2. Compara aceptación y entrega
Si existe un provider_message_id, correlaciónalo con la consulta de la bandeja sintética. Una diferencia pequeña entre ambos puntos indica que el worker funciona; una diferencia grande apunta al proveedor, al buzón o al polling. Este corte ahorra horas de mirar métricas irrelevantes.
3. Revisa reintentos e idempotencia
Un timeout de lectura no demuestra que el mensaje no fue aceptado. Si el worker reintenta sin una clave idempotente, puede crear duplicados y hacer que el test parezca todavía más lento. Marca el intento como «resultado desconocido» cuando no puedas saber si el proveedor lo recibió; luego resuelve ese estado con una consulta o reconciliación.
4. Decide con un límite explícito
Define qué significa «lento» para ese flujo. Por ejemplo, si el objetivo de la prueba es observar una verificación de dos minutos, no dispares un alerta crítica a los diez segundos por una sola muestra. La regla debe considerar ventana, percentil y cantidad mínima de muestras, segun el tráfico esperado, no solo un booleano.
Diseñar alertas que no despierten por ruido
Una alerta útil debe explicar qué hacer. «Email failed» no es un runbook. Un mensaje mejor podría decir: «p99 de entrega sintética sobre 120 s durante 10 minutos; aceptación del proveedor normal; revisar cola de entrega». Esa frase ya contiene la hipótesis inicial.
Separa tres niveles:
- Informativo: una muestra lenta, sin impacto confirmado.
- Advertencia: p95 elevado o cola creciendo durante una ventana estable.
- Crítico: aceptación fallida, expiración de verificaciones o impacto confirmado en usuarios.
Las pruebas sintéticas sin ruido en las alertas ayudan a decidir qué muestras deben abrir un incidente y cuales solo deben alimentar un dashboard. La prueba no necesita correr cada diez segundos si el flujo real dura varios minutos; esa frecuencia solo añade coste y ruido.
Checklist para el siguiente incidente
- ¿Tenemos un
attempt_idque atraviesa aplicación, worker y proveedor? - ¿Separamos aceptación de entrega y de lectura del buzón?
- ¿Medimos p95 o p99 además de la media?
- ¿Podemos distinguir un timeout desconocido de un rechazo confirmado?
- ¿La prueba sintética elimina sus mensajes y sus identificadores después?
- ¿El runbook indica una acción concreta para cada nivel de alerta?
El detalle mas importante es conservar la evidencia suficiente para decidir. Kubernetes no arregla por sí solo una ruta de email mal observada, y reiniciar el deployment casi nunca explica dónde se perdió el tiempo. Con tres marcas de tiempo, una cola visible y un límite razonable, el incidente deja de ser «el correo no llega» y pasa a ser una hipótesis verificable. A veces esta diferencia esta en un solo campo del evento, pero cambia por completo la respuesta.
Top comments (0)