Mihael Costa/índice
← índice
SISTEMAS DISTRIBUIDOS

Event Flow

Un sistema .NET distribuido con dos caras, el producto que usa el cliente y la maquinaria de debajo reaccionando en tiempo real.

  • .NET Aspire
  • MassTransit
  • RabbitMQ
  • SignalR
  • React

Dos vistas de un sistema

Vista del cliente es el producto: un pedido aparece al instante como pendiente y se sigue hasta que se asienta. Si el pago se rechaza, el fallo se resuelve en la interfaz. Si solo va lento —porque el proveedor no contesta y el mensaje se está reintentando—, la interfaz lo dice, con el número de intento.

Vista del sistema son los mismos eventos como maquinaria: cuatro servicios en cadena, cada nodo encendiéndose cuando llega un mensaje, latencia y profundidad de cola reales.

La mayoría de las demos de sistemas distribuidos enseña solo la segunda. Enseñar las dos es el objetivo: el diagrama es la razón de que la experiencia del cliente aguante cuando cae un servicio.

Fallo, a propósito

Hay un botón que tumba el servicio de pagos. Los pedidos se siguen aceptando; el mensaje en curso falla, y MassTransit lo reintenta con backoff exponencial (~1,2 a 8,8s) mientras la cola crece en RabbitMQ. Devuelve los pagos dentro de esos veinte segundos y el mensaje pasa en el siguiente intento. Déjalo, y tras el sexto intento el mensaje aterriza en payments-authorize_error, el pedido pasa a decir “atascado, y no se ha cobrado nada”, y aparece un botón de replay, que deduplica porque cada consumidor escribe una fila de idempotencia en la misma transacción que su trabajo.

Los cuatro patrones que vale la pena nombrar (outbox transaccional, idempotencia del consumidor, reintento con backoff exponencial, dead-letter y replay) son cada uno un archivo pequeño, con el razonamiento junto al código.

Medido, no afirmado

Cada número en pantalla viene de algún sitio real: la latencia del salto es la diferencia entre las marcas de tiempo de envío y recepción; las profundidades de cola vienen de la API de gestión de RabbitMQ; el estado de cada servicio es la respuesta /health de ese servicio —el mismo contrato de cinco campos sobre el que está construido el resto del sitio, generado en C# y TypeScript a partir de un único JSON Schema.

Así que tumbar los pagos cambia el uptime reportado y el estado en la portada del sitio, sin nada cableado a mano para que eso pase.

Dos cosas están simuladas y señaladas en el código: el viaje de ida y vuelta a un proveedor de pagos, y la llamada a un almacén. Todo lo demás, entre el navegador y esas dos líneas, es real.

Sobre el broker

RabbitMQ, autoalojado en un contenedor junto a los servicios y orquestado con .NET Aspire: no cuesta nada de ejecutar.

El trabajo en producción es sobre Azure Service Bus. Los patrones se trasladan sin cambios, porque el outbox, la idempotencia, el backoff y el dead-letter son agnósticos del transporte por construcción; solo cambiaría la línea que nombra el transporte. Service Bus sigue dando sessions y entrega programada en el propio broker, lo que simplifica la maquinaria de reentrega diferida.

p95 en vivo -uptime -