Skip to content

S8 - Mensajería asíncrona entre servicios

1. Introducción

Tiempo: 20 min.

1.1 Propósito

Incorporar comunicación por eventos para desacoplar microservicios y permitir que operaciones de negocio avancen sin depender de una respuesta inmediata.

1.2 Resultado de aprendizaje

El estudiante publica y consume eventos entre microservicios, verifica topics y evidencia procesamiento asíncrono.

1.3 Producto de sesión

Broker de eventos operativo, topics creados y comunicación asíncrona entre orden-ms y pago-ms.

1.4 Motivacion de la sesión

No todas las operaciones requieren una llamada inmediata. Cuando una orden se crea, otros servicios pueden reaccionar por eventos sin bloquear al usuario ni acoplar directamente los servicios.

1.5 Ubicación en el curso

  • Unidad: U2 - Sistema distribuido robusto.
  • Producto de unidad: sistema distribuido seguro, resiliente, consistente, observable e integrado con cliente frontend.
  • Avance del producto en esta sesión: comunicación por eventos entre servicios desacoplados.

2. Explica

Tiempo: 15 min.

2.1 Conceptos clave

  • Mensajería asíncrona.
  • Evento.
  • Productor.
  • Consumidor.
  • Broker.
  • Topic.
  • Desacoplamiento temporal.

2.2 Arquitectura del producto en ecom

En esta sesión se agrega mensajería asíncrona. orden-ms publica eventos de orden y pago-ms los consume. pago-ms también puede publicar eventos de pago para que orden-ms actualice el estado de negocio.

2.2.1 Mensajería en DEV

flowchart TB
    Cliente["Cliente<br/>PowerShell / bash / navegador"]
    Gateway["Gateway<br/>localhost:18080"]
    Config["Config Server<br/>localhost:18888"]
    Eureka["Eureka Server<br/>localhost:18761"]
    Kafka["Kafka broker<br/>localhost:41092"]
    KafkaUI["Kafka UI<br/>localhost:41085"]
    Orden["orden-ms<br/>puerto dinamico"]
    Pago["pago-ms<br/>puerto dinamico"]
    OrdenDB["ecom_orden_db<br/>localhost:15434"]
    PagoDB["ecom_pago_db<br/>localhost:15435"]

    Cliente -->|"POST /api/v1/ordenes"| Gateway
    Gateway --> Orden
    Orden --> OrdenDB
    Orden -->|"publica orden-eventos<br/>spring.kafka.bootstrap-servers<br/>localhost:41092"| Kafka
    Kafka -->|"consume orden-eventos"| Pago
    Pago --> PagoDB
    Pago -->|"publica pago-eventos"| Kafka
    Kafka -->|"consume pago-eventos"| Orden
    KafkaUI -->|"inspecciona topics"| Kafka
    Orden -.->|"spring.config.import<br/>http://localhost:18888"| Config
    Pago -.->|"spring.config.import<br/>http://localhost:18888"| Config
    Orden -.->|"registra instancia<br/>http://localhost:18761/eureka"| Eureka
    Pago -.->|"registra instancia<br/>http://localhost:18761/eureka"| Eureka
    Gateway -.->|"descubre servicios"| Eureka

En DEV, Kafka corre en Docker pero los microservicios corren con Maven en el host:

Kafka broker: localhost:41092
Kafka UI: http://localhost:41085
Microservicios: puerto dinamico

2.2.2 Mensajería en PROD local

flowchart TB
    Cliente["Cliente<br/>PowerShell / bash"]

    subgraph Docker["Docker Network: ecom-prod-net + ecom-kafka-prod-net"]
        Gateway["ecom-gateway<br/>8080 interno<br/>host localhost:28082"]
        Config["ecom-config<br/>8888 interno"]
        Eureka["eureka<br/>8761 interno"]
        Kafka["Kafka broker<br/>kafka:9092<br/>host localhost:29092"]
        KafkaUI["Kafka UI<br/>8080 interno<br/>host localhost:28085"]
        Orden["orden-ms<br/>8080 interno"]
        Pago["pago-ms<br/>8080 interno"]
        OrdenDB["ecom_orden_db"]
        PagoDB["ecom_pago_db"]
    end

    Cliente -->|"POST localhost:28082/api/v1/ordenes"| Gateway
    Gateway --> Orden
    Orden --> OrdenDB
    Orden -->|"publica orden-eventos<br/>spring.kafka.bootstrap-servers<br/>kafka:9092"| Kafka
    Kafka -->|"consume orden-eventos"| Pago
    Pago --> PagoDB
    Pago -->|"publica pago-eventos"| Kafka
    Kafka -->|"consume pago-eventos"| Orden
    KafkaUI -->|"inspecciona topics"| Kafka
    Orden -.->|"spring.config.import<br/>http://ecom-config:8888"| Config
    Pago -.->|"spring.config.import<br/>http://ecom-config:8888"| Config
    Orden -.->|"registra instancia<br/>http://eureka:8761/eureka"| Eureka
    Pago -.->|"registra instancia<br/>http://eureka:8761/eureka"| Eureka
    Gateway -.->|"descubre servicios"| Eureka

2.3 Observabilidad y diagnóstico

Revisar topics, logs de productor, logs de consumidor, Kafka UI y errores de serializacion/deserializacion.

3. Aplica: actividad práctica guiada

Tiempo: 3h.

En el laboratorio, el docente guía la incorporacion de mensajería asíncrona entre orden-ms y pago-ms. El foco es construir el flujo desde cero: levantar Kafka, crear topics, configurar productor/consumidor y probar que el proceso ya no depende de una llamada síncrona directa.

3.1 Preparar el punto de partida

Producto del paso: identificar que el sistema ya tiene Config Server, Eureka, Gateway, seguridad y microservicios base.

Antes de construir eventos, confirma que existan o crea estos módulos:

  • infra/config
  • infra/eureka
  • infra/gateway
  • services/orden-ms
  • services/pago-ms
  • kafka

3.2 Levantar Kafka en DEV

Producto del paso: broker y Kafka UI disponibles para trabajo local.

PowerShell / bash macOS/Linux:

cd kafka
docker compose -f compose-dev.yml up -d
docker compose -f compose-dev.yml ps

3.3 Crear topics base

Producto del paso: topics orden-eventos y pago-eventos creados.

PowerShell / bash macOS/Linux:

docker exec -it ecom-kafka-dev /opt/kafka/bin/kafka-topics.sh --create --topic orden-eventos --bootstrap-server kafka:9092 --partitions 1 --replication-factor 1
docker exec -it ecom-kafka-dev /opt/kafka/bin/kafka-topics.sh --create --topic pago-eventos --bootstrap-server kafka:9092 --partitions 1 --replication-factor 1
docker exec -it ecom-kafka-dev /opt/kafka/bin/kafka-topics.sh --list --bootstrap-server kafka:9092

También puedes revisar Kafka UI:

http://localhost:41085

3.4 Agregar dependencias de mensajería

Producto del paso: orden-ms y pago-ms preparados para usar Kafka.

Agregar en los pom.xml de los microservicios que publican o consumen eventos:

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

3.5 Externalizar configuración de Kafka

Producto del paso: bootstrap server definido por ambiente desde Config Server.

En los archivos de configuración DEV:

spring:
  kafka:
    bootstrap-servers: localhost:41092

En PROD:

spring:
  kafka:
    bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:kafka:9092}

3.6 Crear DTO de evento de orden

Producto del paso: contrato simple para publicar una orden como evento.

Crea:

services/orden-ms/src/main/java/com/upeu/ordenms/evento/EventoOrden.java
services/pago-ms/src/main/java/com/upeu/pagoms/evento/EventoOrden.java

Pega una estructura base:

package com.upeu.ordenms.evento;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventoOrden {
    private String tipoEvento;
    private Long ordenId;
    private Long clienteId;
    private Double total;
    private Long timestamp;
}

3.7 Configurar serializacion JSON

Producto del paso: productor y consumidor comparten formato JSON.

Crea una configuración Kafka en el microservicio productor:

services/orden-ms/src/main/java/com/upeu/ordenms/configuración/KafkaConfiguracion.java

Pega la base:

@Configuration
public class KafkaConfiguracion {

    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Bean
    public ProducerFactory<String, EventoOrden> producerFactory() {
        Map<String, Object> propiedades = new HashMap<>();
        propiedades.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        propiedades.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        propiedades.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
        return new DefaultKafkaProducerFactory<>(propiedades);
    }

    @Bean
    public KafkaTemplate<String, EventoOrden> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }
}

En el consumidor se usa JsonDeserializer y un groupId para leer orden-eventos.

3.8 Implementar productor en orden-ms

Producto del paso: orden-ms publica en orden-eventos cuando se crea una orden.

El productor debe enviar el evento después de persistir la orden. Si la orden no se guarda, no debe publicarse el evento.

Crea:

services/orden-ms/src/main/java/com/upeu/ordenms/servicio/ProductorOrden.java

Fragmento base:

@Service
@RequiredArgsConstructor
public class ProductorOrden {

    private final KafkaTemplate<String, EventoOrden> kafkaTemplate;

    @Value("${app.kafka.topic.ordenes}")
    private String topicOrdenes;

    public void publicarOrdenCreada(EventoOrden eventoOrden) {
        kafkaTemplate.send(topicOrdenes, String.valueOf(eventoOrden.getOrdenId()), eventoOrden);
    }
}

3.9 Implementar consumidor en pago-ms

Producto del paso: pago-ms escucha orden-eventos y registra el intento de pago.

El consumidor debe:

  • Recibir el evento.
  • Registrar logs con correlation id si existe.
  • Guardar o simular el pago.
  • Dejar evidencia en BD o logs.

3.10 Publicar evento de pago

Producto del paso: pago-ms publica resultado en pago-eventos.

El evento de pago debe indicar:

  • ordenId
  • pagoId
  • estadoPago
  • mensaje

3.11 Consumir resultado de pago en orden-ms

Producto del paso: orden-ms actualiza el estado de la orden con base en el pago.

orden-ms debe escuchar pago-eventos y actualizar la orden como confirmada o rechazada.

3.12 Levantar infraestructura DEV

Producto del paso: Config Server, Eureka y Gateway disponibles antes de iniciar microservicios.

PowerShell / bash macOS/Linux:

cd infra/config
mvn spring-boot:run

En otra terminal:

cd infra/eureka
mvn spring-boot:run

En otra terminal:

cd infra/gateway
mvn spring-boot:run

3.13 Levantar microservicios DEV

Producto del paso: orden-ms y pago-ms ejecutando con puertos dinámicos.

PowerShell / bash macOS/Linux:

cd services/orden-ms
mvn spring-boot:run

En otra terminal:

cd services/pago-ms
mvn spring-boot:run

3.14 Probar flujo asíncrono por Gateway

Producto del paso: orden creada, evento publicado y pago procesado por evento.

Ejecutar una solicitud de creación de orden desde shell o Swagger, según los endpoints reales del proyecto. Luego valida:

  • Logs de orden-ms.
  • Logs de pago-ms.
  • Kafka UI.
  • Tablas de orden y pago.

3.15 Probar en PROD local

Producto del paso: flujo de eventos funcionando dentro de Docker.

Levantar primero infraestructura y Kafka PROD, luego microservicios:

cd infra
docker compose up -d --build
cd kafka
docker compose up -d
cd services/orden-ms
docker compose up -d --build
cd services/pago-ms
docker compose up -d --build

3.16 Diagnosticar errores frecuentes

Producto del paso: estudiante reconoce fallos tipicos de mensajería.

Prueba o identifica estos casos:

  • Topic no existe.
  • Broker apagado.
  • Error de serializacion.
  • Consumidor no recibe por groupId.
  • Diferencia entre localhost:41092 en DEV y kafka:9092 en PROD.

3.17 Ruta alternativa: clonar y ejecutar a partir del tag final de la sesión

git clone --branch vs08-mensajeria-asincrona https://github.com/261dist/ecom.git ecom-s08
cd ecom-s08

4. Crea: actividad autónoma

Tiempo: 4h fuera del aula.

Esta actividad autónoma se desarrolla sobre el proyecto de fin de curso del equipo. El producto de la unidad se construye por acumulacion de los avances de cada sesión; por eso, la evidencia de esta sesión debe incorporarse a la documentación del proyecto y quedar trazable en GitHub.

4.1 Plantilla de evidencia individual

Entrega un PDF:

El PDF de esta sesión debe generarse como impresion o exportacion de la sección correspondiente en MkDocs o una herramienta equivalente. No se acepta un PDF armado manualmente fuera de la documentación del proyecto.

S08_Equipo##_ApellidoNombre.pdf

4.1.1 Datos del estudiante

  • Nombre:
  • Equipo:
  • Sesión: S08 - Mensajería asíncrona entre servicios
  • Rol o aporte realizado:
  • Link de GitHub:

4.1.2 Trabajo autónomo realizado

  1. Crear o verificar topics.
  2. Publicar evento desde un microservicio.
  3. Consumir evento en otro microservicio.
  4. Revisar Kafka UI.
  5. Explicar ventaja frente a comunicación síncrona.

4.2 Criterios mínimos de aceptación

  • PDF con nombre correcto.
  • Topics evidenciados.
  • Evento publicado.
  • Evento consumido.
  • Aporte individual verificable.

5. Cierre evaluativo

Tiempo: 20 min.

5.1 Resultados esperados

  • Broker operativo.
  • Topics creados.
  • Productor publica eventos.
  • Consumidor procesa eventos.

5.2 Evidencia del producto de sesión

Entrega individual:

S08_Equipo##_ApellidoNombre.pdf

5.3 Preguntas de defensa y reflexión

  1. Qué diferencia hay entre mensaje y evento?
  2. Por qué la mensajería reduce acoplamiento?
  3. Qué hace un productor?
  4. Qué hace un consumidor?
  5. Cómo diagnosticas que un evento no llega?

5.4 Rúbrica de evaluación

Dimensión Peso 3 - Logro destacado 2 - Logro 1 - Proceso 0 - Inicio Puntuación obtenida
1. Broker y topics 2 Evidencia broker, topics y UI funcionando. Evidencia broker y topics. Evidencia parcial. No evidencia broker.
2. Productor 2 Evento publicado correctamente y explicado. Evento publicado. Publicación parcial. No evidencia productor.
3. Consumidor 2 Evento consumido y procesado correctamente. Evento consumido. Consumo parcial. No evidencia consumidor.
4. Diagnóstico 2 Analiza errores de mensajería con solución. Explica un problema. Menciona problema sin análisis. No diagnostica.
5. Aporte individual 1 Aporte claro y verificable. Aporte identificable. Aporte general. No se identifica aporte.
6. Orden y reflexión 1 PDF ordenado y reflexión técnica clara. Evidencia suficiente. Evidencia poco clara. PDF insuficiente.

Puntuación acumulada = suma de (Peso * Puntuacion obtenida) = ____.

Nota final = (Puntuacion acumulada / 30) * 20 = ____.

Para usar la rúbrica con IA, solicita:

Evalúa el PDF usando la rúbrica de la sesión.
Para cada dimensión selecciona la puntuación obtenida usando la escala Inicio=0, Proceso=1, Logro=2, Logro destacado=3.
Justifica brevemente cada puntuación.
Calcula la puntuación acumulada con la fórmula: suma de (Peso * Puntuación obtenida).
Calcula la nota final sobre 20 con la fórmula: (Puntuación acumulada / 30) * 20.
Indica 2 fortalezas y 2 recomendaciones.