Comunicación asincrónica entre microservicios

Crearemos dos microservicios mediante la comunicación asincrónica. Al realizar la solicitud en el microservicio ms-order, procesará las reglas y, a continuación, emitirá un evento para el ms-payment.

Las aplicaciones basadas en Devprime incorporan de forma nativa un enfoque de “arquitectura basada en eventos” mediante la recepción de eventos externos, el procesamiento de reglas de negocio mediante la emisión de eventos internos y, si es necesario, la propagación de eventos externamente mediante el adaptador Stream que se conecta de forma nativa con RabbitMQ, Kafka y otras plataformas.

En este punto, configuraremos una demostración que involucra dos microservicios. El primero es “Pedido” para recibir pedidos y el segundo es “Pago” para procesar el pago. En el ejemplo, usaremos dos contenedores integrados en docker. Es fundamental cargar los contenedores de MongoDB y RabbitMQ y configurar para agregar la cola “orderevents and paymentevents” en Rabbitmq. Antes de continuar, siga los pasos iniciales instalando la CLI de Devprime.

Si ya tiene servicios de MongoDB/RabbitMQ, cambie la configuración en el archivo /src/App/app/appsettings.json en State and Stream con sus credenciales.

Creación del primer microservicio “Pedido”

Usaremos la Devprime CLI para crear los microservicios. En este ejemplo, escribiremos el nombre de la nueva aplicación, el tipo de servicio Stream como “RabbitMQ” para emitir eventos asincrónicos y el estado como “MongoDB” para la persistencia de datos. Para iniciar un nuevo microservicio, use el ejemplo de comando que se muestra y se creará una nueva aplicación en segundos y estará lista para producción.
dp new Order --stream rabbitmq --state mongodb

Adición de una regla de negocio de Marketplace para acelerar el desarrollo
dp marketplace order

Acelerador de ejecución para la implementación de código basado en el dominio. Cuando ejecute el comando por primera vez en esta demostración, escriba “A” para que pueda continuar y realizar los cambios.
dp init

El acelerador implementa automáticamente las clases de “Domain Events” en Domain, Event Handlers en Application, “Domain Services” en Application, “Application Services” en Application, persistence en State, “API’s” en Web y algunas pruebas unitarias en Tests como ejemplo.

Devprime CLI

Cuando vuelva a ejecutar la aplicación utilizando el script “.\run.ps1” (Windows) o “.\run.sh” (Linux/macOS) ya tendremos una nueva vista de su API. Abra el navegador web en url http://localhost:5000 y ubique el método de publicación en Swagger y haga clic en “Pruébelo”.

Rellene los datos JSON y luego haga clic en “ejecutar”. Vuelva al símbolo del sistema y realice un seguimiento del resultado en el registro de microservicios generado automáticamente por el adaptador de observabilidad de Devprime.

Devprime CLI

Para ver un ejemplo de código implementado por el acelerador, siga el código OrderCreatedEventHandler.cs en la carpeta src/Core/Application/EventHandlers/Order, que proporciona un identificador en el que se conserva el estado de un “pedido” agregado y, a continuación, se notifica a través del adaptador de secuencia.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public override dynamic Handle(OrderCreated orderCreated)
    {
        var success = false;
        var order = orderCreated.Get<Domain.Aggregates.Order.Order>();
        Dp.State.Order.Add(order);
        var destination = Dp.Settings.Default("stream.orderevents");
        var eventName = "OrderCreated";
        var eventData = new OrderCreatedEventDTO()
        {ID = order.ID, CustomerName = order.CustomerName,
        CustomerTaxID = order.CustomerTaxID, Total = order.Total};
        Dp.Stream.Send(destination, eventName, eventData);
        success = true;
        return success;
    }

Microservicio de inicio de Devprime

En este punto, el registro muestra la recepción de una solicitud HTTP en la API “Order”, que se pasa al servicio de aplicación y, a continuación, la regla de negocio en el dominio que procesa y emite el evento “OrderCreated”, que, además de tener el estado persistente en mongo, dio lugar a una notificación en el mundo externo por parte de Stream.

Al ingresar ahora a RabbitMQ a través de su portal, es posible observar este evento en la cola “OrderEvents”. Esto significa que este microservicio ya ha cumplido su rol y notificado este hecho de negocio para que pueda ser percibido por otro servicio.

Debido a que la comunicación en este ejemplo es totalmente asíncrona, si hay eventos en la cola de RabbitMQ, serán leídos por el microservicio “Pago” tan pronto como lo configuremos. Puede detener la aplicación presionando la tecla “Control” + “C” en cualquier momento y volver a cargarla cuando lo desee.

¡¡Enhorabuena!! Ya tienes el microservicio “Pedido”

Creación del segundo microservicio “Pago”

El segundo microservicio se llamará “Pago” y comenzaremos a construirlo en ese momento. Un ítem adicional que haremos durante la implementación es precisamente activar el “subscribe” en el adaptador de Stream para que podamos recibir los eventos emitidos por el microservicio “Order”.

Ejecución del nuevo dp y creación de los microservicios
dp new ms-payment --state mongodb --stream rabbitmq

Adición de una regla de negocio de Marketplace para acelerar el desarrollo
dp marketplace payment

Ejecución del acelerador para la implementación de código basado en dominios
dp init

Dado que ejecutaremos dos microservicios en el mismo entorno local, es necesario cambiar el puerto http de Payment. En la carpeta del proyecto ms-payment, edite el archivo src/App/appsettings.json en la clave web y cámbielo a 5002 y 5003 como ejemplo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  "Devprime_Web": {
    "url": "https://localhost:5003;http://localhost:5002",
    "enable": "true",
    "enableswagger": "true",
    "PostSuccess": "201",
    "PostFailure": "500",
    "GetSuccess": "200",
    "GetFailure": "500",
    "PatchSuccess": "200",
    "PatchFailure": "500",
    "PutSuccess": "200",
    "PutFailure": "500",
    "DeleteSuccess": "200",
    "DeleteFailure": "500"
  },

Ejecute la aplicación con el siguiente comando
.\run.ps1 ou ./run.sh (Linux, MacOS)

Si la aplicación se ha ejecutado, todo está bien. Ciérralo con “Control+C” y continuaremos con las implementaciones para habilitar la recepción de los eventos emitidos por los microservicios “Order”.

El siguiente paso es agregar la configuración al servicio Stream y crear un DTO para recibir los datos del evento. Puede realizar todo el proceso manualmente o utilizando el acelerador que aparece a continuación.
dp add subscribe OrderCreated -as PaymentService

Cuando confirme el cambio, tendrá tres archivos modificados para que podamos avanzar con la configuración.

1
2
3
/src/Core/Application/Services/Payment/Model/OrderCreatedEventDTO.cs
/src/Adapters/Stream/EventStream.cs
/src/Adapters/Stream/GlobalUsings.cs

Abra el archivo Edite el archivo OrderCreatedEventDTO.cs y agregue las propiedades a continuación.
code src\Core\Application\Services\Payment\Model\OrderCreatedEventDTO.cs

1
2
3
4
5
6
public class OrderCreatedEventDTO                     
  {                                                     
    public Guid OrderID { get; set; }
    public string CustomerName { get; set; }
    public double Value { get; set; }  
  }

Ahora edite el archivo “EventStream.cs” estableciendo las propiedades establecidas en OrderCreatedEventDTO. Modificaremos el servicio de aplicación para utilizar el servicio “Agregar”. Esta implementación indica que realizaremos “Subscribe” en el evento denominado “OrderCreated” que se enlazará al alias “Stream1” en el adaptador de Stream.
code src\Adapters\Stream\EventStream.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace Devprime.Stream;
public class EventStream : EventStreamBase, IEventStream
{
    public override void StreamEvents()
    {
        Subscribe<IPaymentService, OrderCreatedEventDTO>("Stream1",
        "OrderCreated", (dto, paymentService, Dp) =>
        {
            var command = new Payment()
            {
                CustomerName = dto.CustomerName,
                OrderID = dto.OrderID,
                Value = dto.Value
            };
            paymentService.Add(command);
        });
    }
}

El último paso es cambiar el archivo de configuración de Stream Adapter en el archivo (src/App/appsettings.json) y agregar el nombre de cola/tema “OrderEvents” en “subscribe” como se muestra en el ejemplo siguiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
"Devprime_Stream": [
    {
      "Alias": "Stream1",
      "Enable": "true",
      "Default": "true",
      "StreamType": "RabbitMQ",
      "HostName": "Localhost",
      "User": "guest",
      "Password": "guest",
      "Port": "5672",
      "Exchange": "Devprime",
      "ExchangeType": "direct",
      "Retry": "3",
      "Fallback": "State1",
      "Subscribe": [ { "Queues": "orderevents" } ]
    }

¡¡Enhorabuena!! Ya tienes los microservicios de “Pago”

Comunicación asincrónica entre microservicios

Ahora ha llegado al gran momento de ejecutar ambos microservicios. Abra cada uno en una ventana y ejecute para aquellos que tienen los servicios activos. Vaya a la URL de microservicios “Ordenar” en http://localhost:5000 y luego vaya a Publicar y haga clic en el botón “Pruébelo”. Haz un post y sigue el increíble resultado con el detalle completo en cada microservicio y Pago reaccionando al evento recibido.

Ahora mismo estamos comprobando el resultado del procesamiento en los microservicios de “Pedido” que reciben
una publicación y emite el evento “OrderCreated”. Todos los detalles son generados automáticamente por el adaptador de observabilidad de Devprime.

[INF][Web]["https://localhost:5001;http://localhost:5000"][Host]["Production"][Parameters]["Appsettings"][RequestId: 3282e6f8-d2bd-4ccf-934a-546276a83038]
[2021-06-19T20:23:07.654-03:00][INF][Web]["HTTP"][Order][Add]["{\n  \"customerName\": \"Ramon\",\n  \"customerTaxID\": \"string\",\n  \"itens\": [\n    {\n      \"description\": \"string\",\n      \"amount\": 0,\n      \"sku\": \"string\",\n      \"price\": 0\n    }\n  ],\n  \"total\": 0\n}"][Origin:"https://localhost:5001/swagger/index.html"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Application][OrderService][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Domain][Order][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Domain][Order][Handle][Event]["OrderCreated"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Application][EventHandler]["OrderCreatedEventHandler"][Event]["OrderCreated"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][State][Type "MongoDB"][Alias "State1"][OrderRepository][Add][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]
[INF][Stream][Type "RabbitMQ"][Alias "Stream1"][Out][Event]["OrderCreated"]["Delivered"]["OrderEvents"]["{\"SagaId\":\"00000000-0000-0000-0000-000000000000\",\"Id\":\"35bc8937-deb8-4e35-a8c4-003171fd6e1b\",\"CorrelationId\":\"06721dfc-fd50-4783-8ea7-df201c22599b\",\"AppId\":\"3282e6f8-d2bd-4ccf-934a-546276a83038\",\"AppName\":\"ms-order\",\"Version\":1,\"Name\":\"OrderCreated\",\"When\":\"2021-06-19T20:23:07.8540357-03:00\",\"Payload\":{\"CustomerName\":\"Ramon\",\"CustomerTaxID\":\"string\",\"Total\":0,\"ID\":\"55a72f16-f4e5-476b-85d9-e86c6e6f390c\"}}"][RequestId: 06721dfc-fd50-4783-8ea7-df201c22599b]

Y ahora llega el momento del evento ‘OrderCreated’ en los microservicios de “Pago”.

[INF][Web]["https://localhost:5003;http://localhost:5002"][Host]["Production"][Parameters]["Appsettings"][RequestId: 072b12e7-c941-4b4b-9823-cbd6e4425309]
[INF][Stream][Type "RabbitMQ"][Alias "Stream1"][In][Event]["OrderCreated"]["OrderEvents"]["{\"SagaId\":\"00000000-0000-0000-0000-000000000000\",\"Id\":\"35bc8937-deb8-4e35-a8c4-003171fd6e1b\",\"CorrelationId\":\"06721dfc-fd50-4783-8ea7-df201c22599b\",\"AppId\":\"3282e6f8-d2bd-4ccf-934a-546276a83038\",\"AppName\":\"ms-order\",\"Version\":1,\"Name\":\"OrderCreated\",\"When\":\"2021-06-19T20:23:07.8540357-03:00\",\"Payload\":{\"CustomerName\":\"Ramon\",\"CustomerTaxID\":\"string\",\"Total\":0,\"ID\":\"55a72f16-f4e5-476b-85d9-e86c6e6f390c\"}}"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Application][PaymentService][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Domain][Payment][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Domain][Payment][Handle][Event]["PaymentCreated"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][Application][EventHandler]["PaymentCreatedEventHandler"][Event]["PaymentCreated"][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]
[INF][State][Type "MongoDB"][Alias "State1"][PaymentRepository][Add][RequestId: 35bc8937-deb8-4e35-a8c4-003171fd6e1b]

Enhorabuena🚀: acaba de desarrollar dos microservicios. Para usar Kafka, simplemente cambie la configuración del adaptador de transmisión.

Última modificación April 11, 2024 (cc33f7e6)