Partilhar via


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

Gorjeta

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

Miniatura da capa do eBook .NET Microservices Architecture for Containerized .NET Applications.

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 pode estar faltando muitos recursos críticos prontos para produção que um barramento de serviço comercial tem.

Uma das implementações personalizadas do barramento de eventos no eShopOnContainers é basicamente uma biblioteca usando a API RabbitMQ. (Há outra implementação baseada no Barramento de Serviço do Azure.)

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 RabbitMQ de um barramento de eventos

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 RabbitMQ de um barramento de evento dev/test de exemplo é um código clichê. 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 é como um método de retorno de chamada no microsserviço atual, além de seu objeto IntegrationEvent relacionado. 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.