DEV Community

Alex Carter
Alex Carter

Posted on

Terraform y CI: alquilar buzones de prueba sin deriva

En muchos equipos de plataforma, Terraform controla la infraestructura con bastante disciplina, pero los datos efímeros de una prueba de email quedan fuera del mapa. El resultado es conocido: un pipeline falla porque dos jobs comparten buzón, un reintento lee el mensaje de la ejecución anterior y el equipo empieza a hablar de “flakiness” sin una causa concreta.

La solución no es meter cada email en el state de Terraform. Eso mezcla dos ciclos de vida muy distintos. Una cuenta de infraestructura puede vivir meses; un buzón de test debería vivir lo que dura una ejecución, o un poco más si necesitamos investigar el fallo. En una operación SRE, esa diferencia es importante.

Este patrón combina Terraform para preparar las capacidades estables y un lease corto para asignar un buzón a cada run de CI. La idea complementa los contratos de email para pruebas repetibles y ayuda a probar emails transaccionales sin mezclar bandejas.

El síntoma: Terraform no ve el problema de CI

Imagina un job que crea un usuario, espera un enlace de verificación y elimina los datos al terminar. Terraform puede haber creado correctamente el namespace, los secretos y los permisos del runner. Aun así, dos ejecuciones paralelas pueden elegir la misma dirección de correo desechable.

El plan de Terraform sale limpio porque no conoce la asignación de mensajes. Tampoco sabe que el job anterior terminó con un timeout y dejó una bandeja abierta. Cuando el segundo job recibe un enlace antiguo, el error aparece como un problema del producto, del proveedor de email o de la latencia. La señal está, pero repartida en varios sistemas.

Un error frecuente es crear un recurso global llamado test-inbox y reutilizarlo en todos los entornos. Funciona durante una demo. Con cinco jobs concurrentes, la identidad de los mensajes ya no es confiable.

Separar infraestructura y lease de ejecución

Terraform debería declarar lo estable: el namespace de pruebas, las políticas de red, el acceso del runner y la configuración no secreta del adaptador de email. El pipeline debería pedir un buzón temporal mediante un servicio o script de leasing.

El lease debe tener cuatro propiedades:

  • Exclusividad: un run_id tiene un buzón y un buzón no tiene dos runs activos.
  • Expiración: si el runner muere, el recurso vuelve al pool después de un TTL.
  • Idempotencia: repetir la petición con el mismo run_id devuelve el mismo lease.
  • Liberación explícita: el finally del job libera el buzón aunque la aserción falle.

Un esquema conceptual en Terraform puede dejar claro el límite:

module "email_test_runtime" {
  source = "./modules/email-test-runtime"

  namespace       = "ci-email-tests"
  max_active_runs = 20
  lease_ttl       = "30m"
  runner_identity = "github-actions"
}
Enter fullscreen mode Exit fullscreen mode

Terraform establece el presupuesto y los permisos. No intenta representar cada dirección creada durante la hora. Esa separación reduce el drift y hace que un plan siga siendo útil.

Un contrato pequeño para cada buzón

Antes de ejecutar el flujo de navegador o API, el job debe guardar un recibo de lease con run_id, dirección, hora de asignación, expiración y versión del contrato. Si la dirección se crea con un servicio de tp mail so, el enlace debe usarse solo para el propósito de testing permitido por el equipo y sin enviar datos reales.

El contrato de mensaje también importa. No basta con buscar el último email. Cada prueba debería filtrar por destinatario, identificador de ejecución y una ventana temporal posterior a la acción que disparó el email. Un asunto parecido no es una identidad.

En la práctica, conviene añadir un prefijo de ejecución al alias o guardar un message_cursor desde el momento del lease. La primera opción ayuda a leer logs; la segunda reduce el riesgo de aceptar un mensaje viejo. A veces se usan las dos, porque la defensa en capas sale más facil de explicar durante un incidente.

Si el código de prueba llama a su fixture dummy e mail, no es un problema por sí mismo, pero sí conviene que el nombre no oculte el contrato real: quién lo posee, cuándo expira y qué evidencia deja. En una búsqueda rápida también pueden aparecer términos como tempail; la operación debe tratar esos nombres como keywords de documentación, no como reglas para aceptar cualquier bandeja.

Qué guardar en el recibo del pipeline

Para investigar un fallo sin repetirlo a ciegas, el artefacto de CI debería incluir:

  1. run_id, commit, entorno y nombre del job.
  2. Identidad del lease y sus timestamps de asignación, renovación y liberación.
  3. Cantidad de mensajes observados, sin guardar cuerpos que contengan datos sensibles.
  4. Razón de aceptación o rechazo de cada candidato.
  5. Código final: passed, expired, timeout o cleanup_failed.

No hace falta conservar toda la bandeja. Un hash del message_id, el asunto redactado y la latencia suelen ser suficientes para empezar. Si los logs también queda retenidos sin un límite, el cleanup se convierte en otro problema de seguridad.

Checklist de operación

  • ¿Terraform define límites, permisos y observabilidad, pero no cada lease efímero?
  • ¿El mismo run_id es idempotente en los reintentos?
  • ¿Existe un TTL para jobs que mueren sin ejecutar cleanup?
  • ¿La prueba filtra por identidad y tiempo, no solo por asunto?
  • ¿El recibo evita cuerpos de email y tokens reales?
  • ¿Una alerta separa lease_exhausted, message_timeout y cleanup_failed?
  • ¿El equipo puede localizar un fallo sin repetir tres veces el job?

Preguntas frecuentes

¿Debo ejecutar Terraform en cada prueba?

No. Ejecútalo cuando cambien la capacidad, los permisos o las políticas del runtime. La asignación de un buzón es una operación de aplicación o de pipeline, con su propio control de concurrencia.

¿Qué ocurre si un lease expira mientras llega el email?

El consumidor debe comprobar el estado del lease antes de aceptar el mensaje. Si está expirado, marca la ejecución como inválida y no recicla automáticamente la evidencia para otro run. Esa regla evita que un correo tardío contamine una prueba nueva.

¿Dónde encaja Kubernetes?

Kubernetes puede ejecutar los jobs y aplicar límites de recursos, pero el contrato de identidad sigue siendo responsabilidad del fixture o del servicio de leasing. Un pod nuevo no debería heredar una bandeja solo porque reutiliza un nombre de deployment.

La lección es simple: Terraform protege la forma estable del sistema; el lease protege la identidad efímera de cada prueba. Cuando ambos límites están escritos y observables, los fallos de email dejan de ser ruido y se vuelven incidentes que se pueden explicar.

Top comments (0)