Síncrono vs eventos
El lunes de Ana
Lunes, 9:02. Ana abre la app de BCPS Bank y envía 100 € a Luis, que también tiene cuenta en el banco. Una transferencia interna: lo más sencillo que hace un banco.
Por dentro, en esa transferencia participa medio banco. Transferenciasver en el mapa recibe la orden. Antes de mover nada pregunta a Antifraudever en el mapa si la operación es de riesgo. Luego pide a Cuentasver en el mapa que cargue 100 € a Ana y abone 100 € a Luis. Y después hay que avisar a Ana (Notificacionesver en el mapa) y dejar constancia para el extracto y la contabilidad (Reportingver en el mapa).
Hay dos formas de conectar todo eso. En la primera, Transferencias llama a cada servicio uno tras otro y espera su respuesta: una cadena de llamadas REST. En la segunda, Transferencias hace lo imprescindible y luego publica un evento, TransferenciaCompletada, en un broker; quien esté interesado se entera por ahí.
Las dos funcionan cuando todo va bien. La pregunta es qué pasa cuando no, y a quién le toca pagarlo. Abajo tienes las dos versiones, una junto a la otra, ejecutando la misma transferencia. Rómpelas.
La misma transferencia, dos veces
Cada vez que pulsas Enviar, Ana envía 100 € a Luis en los dos modelos a la vez. Cambia el estado de los servicios antes de enviar: lento tarda 1,5 s en responder; caído no responde. Mira tres cosas: cuánto espera Ana, qué le dice la app y qué pasa con su dinero. Si va demasiado rápido, baja la velocidad o activa paso a paso.
Qué ha pasado
Lo que es igual en los dos
Fíjate primero en lo que no cambia. En los dos modelos, Transferencias llama a Antifraude y a Cuentas y espera su respuesta. No es un descuido del modelo de eventos: es que necesita esas respuestas para seguir. No puede mover el dinero sin saber si la operación es de riesgo, y no puede decirle a Ana «hecho» sin saber si Cuentas lo ha hecho.
Y en los dos, Cuentas registra el cargo a Ana y el abono a Luis en una sola transacción de base de datos. O se aplican los dos movimientos o ninguno. El dinero nunca queda a medias; lo que puede salir mal está en lo que pasa después.
Todos vivos a la vez
En la cadena REST, para que la transferencia termine bien tienen que estar funcionando en ese mismo momento Antifraude, Cuentas, Notificaciones y Reporting. Basta con que uno falle para que falle todo. A esto se le llama acoplamiento temporal.
Se nota en los números. Si cada servicio está disponible el 99,9 % del tiempo (unos 43 minutos caído al mes), la cadena solo funciona cuando funcionan todos, y las probabilidades se multiplican:
| De qué depende la transferencia | Disponibilidad | Sin transferencias, al mes |
|---|---|---|
| Un solo servicio | 99,9 % | ≈ 43 min |
| Eventos: Antifraude, Cuentas y el broker | 0,999³ ≈ 99,7 % | ≈ 2,2 h |
| REST: Antifraude, Cuentas, Notificaciones, Reporting y Fidelización | 0,999⁵ ≈ 99,5 % | ≈ 3,6 h |
Con eventos, la transferencia sigue dependiendo de Antifraude y Cuentas (porque debe) y ahora también del broker. A cambio, deja de depender de Notificaciones, Reporting y Fidelización. Y cada consumidor nuevo ya no resta disponibilidad a la transferencia. Por eso el broker se monta replicado: pasa a ser una pieza crítica.
El error que miente
Con Notificaciones caído, la app de Ana dice «error». Pero el dinero ya había salido de su cuenta: Cuentas hizo su parte antes de que Transferencias intentara avisar a nadie. El error no dice la verdad sobre lo que ha pasado.
Y Ana hace lo que haría cualquiera ante un error: reintentar. La segunda vez, Cuentas vuelve a mover 100 €. Ahora Luis ha recibido 200 € y Ana solo quería enviar 100. Esto es una transferencia duplicada, y en un banco es de los peores fallos posibles.probar en el laboratorio
El duplicado se queda sin resolver a propósito. Evitar que el mismo intento se ejecute dos veces se llama idempotencia y es el tema del episodio 4. Spoiler: los eventos tampoco te libran del todo, porque un broker puede entregar el mismo evento dos veces.
¿Y si Transferencias captura el error de Notificaciones y responde «OK» igualmente? Es lo que haría un buen equipo con REST, y resuelve el error falso. Pero entonces el aviso a Ana se pierde sin que nadie se entere. Para no perderlo tendrías que guardarlo y reintentarlo más tarde… y eso es construir una cola a mano.
Las latencias se suman
En una cadena síncrona, Ana espera la suma de todo: Antifraude, más Cuentas, más Notificaciones, más Reporting. Si Reporting tarda un segundo y medio porque está generando un informe, Ana espera un segundo y medio más para algo que no le afecta en absoluto.probar en el laboratorio
Con eventos, Ana solo espera lo imprescindible. El resto ocurre después de responderle. Pero ralentiza Antifraude: Ana espera en los dos modelos. Los eventos no aceleran lo que de verdad necesitas esperar.probar en el laboratorio
Quién conoce a quién
Añadir Fidelización en REST significa cambiar el código de Transferencias y volver a desplegarlo. El equipo de Transferencias tiene que conocer a cada interesado, llamarlo y decidir qué hacer si falla. Cada consumidor nuevo es trabajo para ellos y un riesgo más para su servicio.
Con eventos, Fidelización se suscribe a TransferenciaCompletada y Transferencias ni se entera.probar en el laboratorio Transferencias anuncia lo que ha pasado; lo que hagan los demás con eso ya no es problema suyo.
Lo que cuestan los eventos
Hasta aquí parece que los eventos solo tienen ventajas. No es así:
- Consistencia eventual. Ana ve «hecho» antes de que Reporting sepa nada. Durante un rato, el extracto no refleja la transferencia. Casi siempre da igual, pero hay que saberlo y diseñar para ello.
- Transferencias pierde la respuesta. No sabe si el aviso se envió. Si eso le importa (por ejemplo, porque la ley exige avisar), un evento no es la herramienta.
- Una pieza más. El broker hay que operarlo, vigilarlo y replicarlo, y si se cae, no hay transferencias.
- Más difícil de seguir. En REST, el flujo está en una función. Con eventos está repartido entre varios servicios, y entender qué pasó con una transferencia exige trazas y herramientas.
Criterio
La pregunta no es «¿REST o eventos?» para todo el sistema, sino para cada relación entre dos servicios. Recorre estas preguntas en orden:
-
¿Necesitas su respuesta para decidir qué haces a continuación?Transferencias no puede mover dinero sin saber el riesgo.síncrono
-
¿Si el otro falla, tu operación también debe fallar?Sin evaluación de riesgo, el banco prefiere rechazar.síncrono
-
¿Es una reacción a algo que ya ha pasado, y puede ocurrir un poco más tarde?Avisar a Ana, alimentar el extracto, sumar puntos.evento
-
¿Pueden aparecer más interesados que tú no controlas?Hoy Fidelización; mañana, quién sabe.evento
- Cualquiera de los dos vale. Elige lo más simple: normalmente, una llamada.
Aplicado a la transferencia de Ana:
| Relación | Modelo | Por qué |
|---|---|---|
| Transferencias → Antifraude | síncrono | Sin evaluación de riesgo no se mueve dinero. Si Antifraude falla, rechazar es lo correcto. |
| Transferencias → Cuentas | síncrono | Hay que saber si el dinero se movió antes de responder a Ana. |
| Transferencias → Notificaciones | evento | El aviso puede llegar unos segundos tarde. Que falle no debe tumbar la transferencia. |
| Transferencias → Reporting | evento | El extracto puede ir con retraso. Reporting no debe hacer esperar a Ana. |
| Transferencias → Fidelización | evento | Consumidor que aparece después. Transferencias no debería ni saber que existe. |
Dos señales de que has elegido mal:
- Síncrono de más: la operación principal falla o va lenta por culpa de un servicio secundario. Es lo que le pasó a Ana con Notificaciones.
- Eventos de más: publicas un evento y luego te quedas esperando otro evento de vuelta mientras el usuario mira un indicador de carga. Eso es una llamada síncrona disfrazada, con más piezas y más difícil de depurar.
En el mundo real
El broker genérico de la simulación existe en muchas versiones. Las más conocidas son Apache Kafka, RabbitMQ, Amazon SQS (a menudo junto a SNS), Google Cloud Pub/Sub y Azure Service Bus. No son intercambiables: unos guardan los eventos como un historial que se puede releer y otros los borran al entregarlos. Esa diferencia es el tema del episodio 5.
Para la parte síncrona, lo habitual es REST sobre HTTP o gRPC. Casi ningún sistema real es solo una cosa o solo la otra: la mezcla de la simulación, con llamadas donde hace falta la respuesta y eventos para el resto, es el caso normal.
Y lo has visto como cliente. La notificación push de tu banco llega unos segundos después de hacer la transferencia, y a veces el movimiento tarda en aparecer en el extracto. No es que el banco sea lento: está funcionando exactamente como el panel de eventos.
Siguiente episodio
En la simulación han aparecido dos tipos de mensaje sin que nos paremos en ellos. cuentas.moverDinero es una orden: «haz esto». TransferenciaCompletada es un hecho: «esto ha pasado». No son lo mismo, y confundirlos es una fuente clásica de problemas.
TransferenciaCompletada para que Fidelización no tenga que preguntar a nadie? ¿Y por qué Fidelización no escucha MovimientoRegistrado, que también cuenta que se ha movido dinero?
¿Y la transferencia duplicada de Ana? Sigue pendiente. La resolvemos en el episodio 4, Cuando algo falla a mitad.