Partilhar via


Implementando um barramento de eventos com RabbitMQ para o ambiente de desenvolvimento ou teste

Sugestão

Este conteúdo é um trecho do eBook, .NET Microservices Architecture for Containerized .NET Applications, disponível no do .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Miniatura da capa do eBook Arquitetura de Microsserviços .NET para Aplicações .NET Contentorizadas.

Devemos começar dizendo que, se você criar seu barramento de eventos personalizado com base no RabbitMQ em execução em um contêiner, como o aplicativo eShopOnContainers faz, ele deve ser usado apenas para seus ambientes de desenvolvimento e teste. Não o use para seu ambiente de produção, a menos que você o esteja criando como parte de um barramento de serviço pronto para produção, conforme descrito na seção Recursos adicionais abaixo. Um barramento de eventos personalizado simples poderá faltar muitos recursos críticos preparados para produção que um barramento de serviço comercial possui.

Uma das implementações personalizadas do barramento de eventos no eShopOnContainers é basicamente uma biblioteca usando a API RabbitMQ. Existe outra implementação baseada no Azure Service Bus.

A implementação do barramento de eventos com o RabbitMQ permite que os microsserviços assinem eventos, publiquem eventos e recebam eventos, como mostra a Figura 6-21.

Diagrama mostrando RabbitMQ entre o emissor e o recetor da mensagem.

Figura 6-21. Implementação de um barramento de eventos no RabbitMQ

O RabbitMQ funciona como um intermediário entre o editor de mensagens e os assinantes, para lidar com a distribuição. No código, a classe EventBusRabbitMQ implementa a interface IEventBus genérica. Essa implementação é baseada na injeção de dependência para que você possa trocar desta versão de desenvolvimento/teste para uma versão de produção.

public class EventBusRabbitMQ : IEventBus, IDisposable
{
    // Implementation using RabbitMQ API
    //...
}

A implementação do RabbitMQ de um barramento de eventos dev/test de exemplo é um código padrão. Ele tem que lidar com a conexão com o servidor RabbitMQ e fornecer código para publicar um evento de mensagem para as filas. Ele também tem que implementar um dicionário de coleções de manipuladores de eventos de integração para cada tipo de evento; esses tipos de evento podem ter uma instanciação diferente e assinaturas diferentes para cada microsserviço do recetor, como mostra a Figura 6-21.

Implementando um método de publicação simples com RabbitMQ

O código a seguir é uma versão simplificada de uma implementação de barramento de eventos para RabbitMQ, para mostrar todo o cenário. Você realmente não lida com a conexão dessa maneira. Para ver a implementação completa, consulte o código real no repositório dotnet-architecture/eShopOnContainers .

public class EventBusRabbitMQ : IEventBus, IDisposable
{
    // Member objects and other methods ...
    // ...

    public void Publish(IntegrationEvent @event)
    {
        var eventName = @event.GetType().Name;
        var factory = new ConnectionFactory() { HostName = _connectionString };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: _brokerName,
                type: "direct");
            string message = JsonConvert.SerializeObject(@event);
            var body = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish(exchange: _brokerName,
                routingKey: eventName,
                basicProperties: null,
                body: body);
       }
    }
}

O código real do método Publish no aplicativo eShopOnContainers é melhorado usando uma política de repetição Polly , que tenta novamente a tarefa algumas vezes caso o contêiner RabbitMQ não esteja pronto. Esse cenário pode ocorrer quando o docker-compose está iniciando os contêineres; por exemplo, o contêiner RabbitMQ pode começar mais lentamente do que os outros contêineres.

Como mencionado anteriormente, há muitas configurações possíveis no RabbitMQ, portanto, esse código deve ser usado apenas para ambientes de desenvolvimento/teste.

Implementando o código de assinatura com a API RabbitMQ

Assim como o código de publicação, o código a seguir é uma simplificação de parte da implementação do barramento de eventos para RabbitMQ. Novamente, você geralmente não precisa mudá-lo, a menos que você esteja melhorando-o.

public class EventBusRabbitMQ : IEventBus, IDisposable
{
    // Member objects and other methods ...
    // ...

    public void Subscribe<T, TH>()
        where T : IntegrationEvent
        where TH : IIntegrationEventHandler<T>
    {
        var eventName = _subsManager.GetEventKey<T>();

        var containsKey = _subsManager.HasSubscriptionsForEvent(eventName);
        if (!containsKey)
        {
            if (!_persistentConnection.IsConnected)
            {
                _persistentConnection.TryConnect();
            }

            using (var channel = _persistentConnection.CreateModel())
            {
                channel.QueueBind(queue: _queueName,
                                    exchange: BROKER_NAME,
                                    routingKey: eventName);
            }
        }

        _subsManager.AddSubscription<T, TH>();
    }
}

Cada tipo de evento tem um canal relacionado para obter eventos do RabbitMQ. Em seguida, você pode ter quantos manipuladores de eventos por canal e tipo de evento forem necessários.

O método Subscribe aceita um objeto IIntegrationEventHandler, que funciona como um método de retorno de chamada no microsserviço atual, juntamente com o seu objeto relacionado, IntegrationEvent. Em seguida, o código adiciona esse manipulador de eventos à lista de manipuladores de eventos que cada tipo de evento de integração pode ter por microsserviço cliente. Se o código do cliente ainda não tiver sido inscrito no evento, o código criará um canal para o tipo de evento para que ele possa receber eventos em um estilo push do RabbitMQ quando esse evento for publicado de qualquer outro serviço.

Como mencionado acima, o barramento de evento implementado no eShopOnContainers tem apenas um propósito educacional, uma vez que lida apenas com os cenários principais, portanto, não está pronto para produção.

Para cenários de produção, verifique os recursos adicionais abaixo, específicos para RabbitMQ, e a seção Implementando comunicação baseada em eventos entre microsserviços .

Recursos adicionais

Uma solução pronta para produção com suporte para RabbitMQ.