DEV Community

Alex Carter
Alex Carter

Posted on

Un SLO para emails de CI en Kubernetes

Las pruebas de email en CI fallan de una forma engañosa: el job termina en verde, pero el mensaje de verificación nunca llega a la bandeja que el test está leyendo. Un SLO pequeño y medible convierte ese misterio en un incidente operable.

El síntoma: CI verde, correo perdido

En un pipeline de Kubernetes es habitual que el test haga tres cosas: crea un usuario, solicita un enlace y espera el mensaje. Cuando la espera expira, parece un fallo de aplicación. Sin embargo, hay varias capas entre la petición y la aserción:

  1. El servicio publica el mensaje.
  2. La cola acepta o rechaza el trabajo.
  3. El worker procesa el mensaje.
  4. El buzón de prueba lo hace visible.
  5. El test encuentra el mensaje correcto y consume el código.

Si todas esas etapas comparten un único timeout, el equipo no sabe donde se perdió el correo. Además, reintentar todo el job añade ruido y alarga la cola.

La primera lección de SRE es sencilla: no llames "email enviado" a cinco estados diferentes.

Define el SLO antes de tocar Kubernetes

Para una suite de integración, un SLO razonable puede ser: "el 99% de los mensajes aparecen en el buzón correcto en menos de 30 segundos". Lo importante es que tenga un punto de inicio, un punto de fin y una ventana clara.

En este caso:

  • Inicio: el API confirma que aceptó la solicitud de envío.
  • Fin: el test encuentra un mensaje con run_id, destinatario y tipo esperados.
  • Error: se supera el límite o aparece un mensaje de otra ejecución.

No midas solo la latencia media. Un p95 alto suele explicar mejor la experiencia del pipeline, y el porcentaje de mensajes que nunca aparecen muestra si hay una pérdida real. Para un fixture creado con tempmail.so o con un stub local, la regla es la misma: cada mensaje necesita identidad y trazabilidad.

El alerta importante no es "hay un pod reiniciando". Es "la tasa de mensajes localizados bajó y el presupuesto de error se está consumiendo".

Separa entrega, lectura y diagnóstico

En los logs, registra un identificador de ejecución estable, por ejemplo ci-2026-10-07-1842, pero no pongas tokens completos ni datos personales. Una métrica útil puede tener estas dimensiones:

  • environment y namespace;
  • provider o transporte usado;
  • message_type, como signup o password_reset;
  • result, con valores found, timeout o duplicate.

La lectura también debe ser explícita. Un test no debería preguntar "¿hay algún correo nuevo?"; debe buscar el mensaje del run_id y avanzar un cursor o un received_at conocido. De ese modo, un correo viejo no hace que el pipeline pase por accidente.

Cuando el procesamiento tiene varias etapas, una cola observable ayuda mucho más que subir el timeout. Este patrón de colas visibles para trabajos de email largos permite distinguir un retraso del proveedor de un worker atascado.

Instrumentación mínima para un email confiable

Antes de abrir dashboards nuevos, añade cuatro marcas de tiempo al evento:

requested_at
accepted_at
processed_at
visible_at
Enter fullscreen mode Exit fullscreen mode

Con ellas puedes calcular dónde se consume el presupuesto. Si accepted_at falta, el problema está en el API o en la conexión. Si falta processed_at, revisa la cola y el worker. Si existe processed_at pero no visible_at, mira el adaptador del buzón o el aislamiento entre ejecuciones.

En Kubernetes, añade al menos:

  • una métrica de profundidad y antigüedad de la cola;
  • un contador de reintentos y mensajes descartados;
  • un log estructurado por run_id;
  • una alerta cuando el p95 de visibilidad supera el SLO;
  • un límite de retención para fixtures y logs.

Los dashboards se vuelve ruido si solo agregan gráficos. Cada panel debe responder una pregunta: "¿se perdió el mensaje antes o despues del worker?".

Si el flujo usa un agente o una herramienta que dispara el envío, documenta el contrato de entrada y salida. Los contratos de tools resistentes a fallos son útiles incluso fuera de LLMs: dejan claro qué significa aceptar una operación y qué evidencia debe quedar.

Un runbook que no dependa de héroes

Cuando una alerta se active, el operador debería seguir una secuencia corta:

  1. Confirmar si el fallo afecta a una namespace o a todo el entorno.
  2. Buscar el run_id en API, cola, worker y buzón.
  3. Comparar accepted_at con processed_at y visible_at.
  4. Revisar duplicados, reintentos y la antigüedad del mensaje.
  5. Pausar nuevos despliegues si el presupuesto de error sigue cayendo.
  6. Guardar el recibo de la ejecución antes de limpiar los datos.

No borres el fixture antes de saber qué ocurrió. La limpieza automática debe esperar a que exista un recibo mínimo. Una consulta como "tempail mail" puede aparecer en reportes, pero no debe mezclarse con nombres de métricas ni claves del sistema.

Un fallo que ocurre solo en la madrugada merece la misma evidencia que uno en horario laboral. A veces una alerta rapida se resuelve con un vistazo; otras veces el retraso solo aparece despues de varios reintentos.

Preguntas frecuentes

¿Debo hacer que el SLO sea de 100%?

No suele ser práctico. Un 100% convierte cualquier fallo aislado en una crisis y anima a esconder errores con reintentos infinitos. Define un objetivo alto, pero conserva un presupuesto de error que permita investigar sin bloquear cada merge.

¿Un timeout más largo arregla el problema?

Solo si el sistema es sano y la variación es esperable. Si la cola crece o hay mensajes duplicados, aumentar el timeout oculta la causa. Primero separa las etapas y observa donde se consume el tiempo.

¿Qué hago con mensajes que llegan despues de que termina el test?

Marca la ejecución como fallida, conserva el recibo y limpia el fixture con una política de retención. No reutilices esa bandeja en la siguiente ejecución: mezclar estados hace que el diagnóstico sea mucho más dificil.

Checklist de implementación

  • [ ] Cada email de prueba lleva run_id, tipo y destinatario aislado.
  • [ ] El SLO tiene inicio, fin y ventana de medición.
  • [ ] Se miden accepted_at, processed_at y visible_at.
  • [ ] El test busca un mensaje específico, no el más reciente.
  • [ ] Hay métricas para cola, reintentos, duplicados y timeouts.
  • [ ] La alerta apunta a una acción del runbook.
  • [ ] El recibo se conserva antes de limpiar el fixture.

La meta no es conseguir que los emails de CI sean mágicamente instantáneos. Es saber, con evidencia, si falló la aplicación, la cola, el worker o la lectura del buzón. Ese límite claro hace que Kubernetes sea más predecible y que el equipo pueda mejorar el pipeline sin perseguir síntomas.

Top comments (0)