DEV Community

Alex Carter
Alex Carter

Posted on

Kubernetes: contrato de email para cada ejecución

En un pipeline de CI, un email de verificación parece una dependencia pequeña. El pod crea un usuario, espera el mensaje y continúa. Pero cuando varias ejecuciones comparten buzón, el resultado verde puede esconder un problema: una prueba leyó el mensaje de otra ejecución.

En equipos de plataforma trato el correo de prueba como un recurso con contrato, igual que un volumen temporal o una dirección IP. Cada ejecución debe declarar quién es, qué buzón puede leer, qué mensaje espera y cuándo deja de ser válido. Esta regla hace que una incidencia sea explicable incluso cuando el pod ya terminó.

El patrón funciona con un servicio de temp mail.so o con un capturador dentro del clúster. Lo importante es la frontera de confianza y la evidencia que deja cada ejecución.

El síntoma: el pod está verde, pero el email no llegó

Un fallo típico empieza con un mensaje como “verification email not found”. El equipo aumenta el timeout y reintenta. A veces la prueba pasa, pero solo porque encontró un mensaje antiguo. Otras veces dos pods consumen el mismo correo y el resultado cambia según el orden de ejecución.

La señal útil no es únicamente si llegó un email. Necesitamos saber:

  • qué ejecución pidió el mensaje;
  • qué dirección o alias estaba reservado;
  • cuándo se envió la solicitud;
  • qué mensajes fueron observados;
  • cuál era el identificador esperado;
  • cuándo expiró la reserva.

Sin esos datos, una cadena como tamp mail com puede aparecer en un ticket sin que sepamos si describe un alias o una búsqueda manual. La prueba queda verde o roja, pero no necesariamente correcta.

Qué debe contener el contrato de una ejecución

Un contrato pequeño evita que cada test invente su propia política. Para cada ejecución guardo un manifiesto con cinco campos:

  1. Identidad: un run_id único, el nombre del test y el índice del worker.
  2. Propiedad: la dirección reservada y el consumidor autorizado.
  3. Expectativa: asunto, destinatario y un token de correlación.
  4. Tiempo: created_at, límite de espera y expires_at.
  5. Resultado: mensaje reclamado, motivo de fallo y limpieza realizada.

El token de correlación debe pertenecer a la ejecución, no solo al usuario de prueba. Un asunto como “Verify your account” es demasiado común. Un identificador corto del run es más fácil de filtrar y no depende del orden del proveedor.

Conviene que el contrato tenga estados explícitos: reserved, waiting, claimed, expired y released. Si la ejecución pasa de waiting a expired, el sistema debe explicar esa transición. No devería convertirla silenciosamente en otro intento con la misma dirección.

Un manifiesto de email para Kubernetes

El manifiesto no necesita ser un recurso CRD. Puede ser un archivo JSON generado por el job y publicado como artefacto junto con los logs del pod; así resulta mas facil comparar ejecuciones:

{
  "run_id": "checkout-1842-07",
  "owner": "worker-07",
  "mailbox": "checkout-1842-07@example.test",
  "expected": {
    "recipient": "checkout-1842-07@example.test",
    "subject_token": "run-1842-07"
  },
  "created_at": "2026-10-17T05:00:00Z",
  "expires_at": "2026-10-17T05:02:00Z",
  "state": "waiting"
}
Enter fullscreen mode Exit fullscreen mode

El pod debe comprobar la expiración antes de cada lectura. El sidecar o servicio de correo puede registrar el mismo run_id, pero no debería aceptar un mensaje sin una propiedad válida. Así se reduce el riesgo de que un retry lea la bandeja de la ejecución anterior.

Para el aislamiento del entorno, recomiendo una dirección por run cuando el proveedor lo permite. Si solo existe un buzón compartido, usa aliases, tokens de correlación y una política de reclamación atómica. La práctica de aislar pruebas de email por entorno ayuda a separar esta decisión de la lógica de la aplicación.

Cómo diagnosticar el fallo sin reintentar a ciegas

Cuando una prueba falla, reviso las evidencias en este orden:

  1. Comparo created_at, entrega y expires_at.
  2. Verifico destinatario y token, no solo el asunto.
  3. Busco otro pod que tenga la misma dirección o run_id.
  4. Compruebo si la reclamación fue atómica.
  5. Reviso si el cleanup ocurrió antes de guardar el artefacto.

Si el mensaje llegó después de expirar, es un problema de latencia o del presupuesto de espera. Si llegó a tiempo pero el token no coincide, hay contaminación entre ejecuciones o un bug en el productor. Si la aplicación falló después de reclamarlo, el buzón probablemente no es la causa.

Este orden evita subir todos los timeouts. Un timeout más largo puede ocultar el síntoma y hacer el pipeline mas lento. Primero hay que medir; luego ajustar el presupuesto con una razón concreta. Tambien conviene mostrar estos datos en el resumen del job, no enterrarlos en un log de veinte mil líneas.

Checklist para SRE y equipos de plataforma

Antes de dar por confiable una prueba de email en Kubernetes, compruebo:

  • cada ejecución tiene un run_id y una dirección propia, o una regla de aislamiento equivalente;
  • el contrato registra propietario, token, expiración y estado;
  • el polling empieza después de la acción que dispara el mensaje;
  • la reclamación valida destinatario y correlación;
  • una expiración produce un error específico, no un retry infinito;
  • los artefactos sobreviven al borrado del pod;
  • el cleanup ocurre después de guardar la evidencia;
  • las métricas distinguen demora, contaminación y fallo de la aplicación;
  • el próximo run no puede reutilizar un buzón todavía reservado.

La interfaz del test también importa. Un estado de carga claro y un error de email que no mueve el layout, como explica errores de email sin mover el layout, reduce el ruido durante la depuración manual. Es la misma idea en otra capa: un estado visible debe corresponder con un estado real.

Algunos equipos escriben dummy e mail en scripts o notas. No pasa nada por ese texto, pero no debe convertirse en una identidad compartida ni en una regla de búsqueda. Las convenciones pueden ser imperfectas; el contrato de ownership no.

Preguntas frecuentes

¿Es mejor crear un buzón por pod o por test?

Por test suele dar un diagnóstico más limpio. Por pod puede ser suficiente si el worker ejecuta una sola prueba y el aislamiento está garantizado. La elección debe seguir el nivel real de paralelismo.

¿Cuánto debe durar la reserva?

Empieza con el tiempo normal de entrega más un margen pequeño. Mide los casos lentos y revisa el valor segun la latencia observada. Una reserva muy larga deja vivir datos obsoletos; una muy corta produce falsos fallos.

¿Qué hago si el proveedor solo ofrece un buzón compartido?

Usa aliases o tokens únicos, reclamación atómica y un manifiesto por ejecución. Si no puedes garantizar ninguna de esas fronteras, trata el buzón como una dependencia limitada y registra esa limitación como riesgo del pipeline.

Top comments (0)