Brighter 与 RabbitMQ 集成指南

RabbitMQ 简介  

RabbitMQ 是最广泛使用的消息代理之一,实现了高级消息队列协议(AMQP),以确保可靠的消息传递。它基于 Erlang 编程语言构建,具备高可扩展性和容错能力,非常适合分布式系统。RabbitMQ 作为中介,从生产者接收消息并将其传递给消费者,从而在微服务架构中解耦服务。

要求  

Brighter 回顾  

在继续 RabbitMQ 配置之前,先回顾一下我们已知的 Brighter 核心概念。

请求(命令/事件)  

通过 IRequest 定义消息:

public class Greeting() : Event(Guid.NewGuid())
{
    public string Name { get; set; } = string.Empty;
}
  • 命令:单接收者操作(例如 SendEmail)。  
  • 事件:广播通知(例如 OrderShipped)。

消息映射器  

在 Brighter 消息与应用程序对象之间转换:

public class GreetingMapper : IAmAMessageMapper<Greeting>
{
    public Message MapToMessage(Greeting request)
    {
        var header = new MessageHeader();
        header.Id = request.Id; 
        header.TimeStamp = DateTime.UtcNow;
        header.Topic = "greeting.topic"; // 目标主题
        header.MessageType = MessageType.MT_EVENT;

        var body = new MessageBody(JsonSerializer.Serialize(request));
        return new Message(header, body);
    }

    public Greeting MapToRequest(Message message)
    {
        return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
    }
}

请求处理器  

处理传入消息:  

public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandler<Greeting>
{
    public override Greeting Handle(Greeting command)
    {
        logger.LogInformation("你好 {Name}", command.Name);
        return base.Handle(command);
    }
}

使用 RabbitMQ 配置 Brighter  

1. 连接设置

 定义 RabbitMQ 连接信息:  

var connection = new RmqMessagingGatewayConnection
{
    AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
    Exchange = new Exchange("paramore.brighter.exchange"),
};

2. RabbitMQ 订阅  

订阅队列/主题:

.AddServiceActivator(opt =>
{
    opt.Subscriptions = [
       new RmqSubscription<Greeting>(
           new SubscriptionName("kafka.greeting.subscription"),
           new ChannelName("greeting.queue"),
           new RoutingKey("greeting.topic"),
           makeChannels: OnMissingChannel.Create
       ),
    ];

    opt.ChannelFactory = new ChannelFactory(
                        new RmqMessageConsumerFactory(connection)
                    );
})

3. RabbitMQ 生产者配置  

发布事件到主题:  

.UseExternalBus(new RmqProducerRegistryFactory(connection, new[]
            {
                new RmqPublication
                {
                    Topic = new RoutingKey("greeting.topic"),
                    MakeChannels = OnMissingChannel.Create
                }
            }).Create());

最佳实践  

  • 死信队列(DLQ):在 RabbitMQ 中配置 DLQ 以处理有毒消息。在队列声明中使用 `deadLetterChannelName` 和 `deadLetterRoutingKey`。  
  • 监控:使用 RabbitMQ 的管理插件跟踪队列健康状态和性能。  
  • 错误处理:实现重试和断路器以处理瞬时故障(Brighter 通过属性支持重试和断路器,后续文章将展示)。

结论 

将 Brighter 与 RabbitMQ 集成可在 .NET 应用程序中实现稳健、可扩展的消息传递。通过利用 RabbitMQ 的 AMQP 协议和 Brighter 的抽象层,您可以:  

  • 通过发布-订阅模式解耦服务。  
  • 确保消息顺序和可靠性。  
  • 通过 DLQ 和重试简化错误处理。  

在生产环境中使用时,需根据 Brighter 的最新文档验证 RabbitMQ 配置,因为功能(如消息优先级或延迟交换)可能随版本演进。

参考  

using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessagingGateway.RMQ;
using Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection;
using Paramore.Brighter.ServiceActivator.Extensions.Hosting;
using Serilog;

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .Enrich.FromLogContext()
    .WriteTo.Console()
    .CreateLogger();

var host = new HostBuilder()
    .UseSerilog()
    .ConfigureServices(
        (ctx, services) =>
        {
            var connection = new RmqMessagingGatewayConnection
            {
                AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
                Exchange = new Exchange("paramore.brighter.exchange"),
            };

            services
                .AddHostedService<ServiceActivatorHostedService>()
                .AddServiceActivator(opt =>
                {
                    opt.Subscriptions =
                    [
                        new RmqSubscription<Greeting>(
                            new SubscriptionName("kafka.greeting.subscription"),
                            new ChannelName("greeting.topic"),
                            new RoutingKey("greeting.topic"),
                            makeChannels: OnMissingChannel.Create
                        ),
                    ];

                    opt.ChannelFactory = new ChannelFactory(
                        new RmqMessageConsumerFactory(connection)
                    );
                })
                .AutoFromAssemblies()
                .UseExternalBus(
                    new RmqProducerRegistryFactory(
                        connection,
                        [
                            new RmqPublication 
                            {
                                MakeChannels = OnMissingChannel.Create,
                                Topic = new RoutingKey("greeting.topic"),
                            },
                        ]
                    ).Create()
                );
        }
    )
    .Build();

await host.StartAsync();

while (true)
{
    await Task.Delay(TimeSpan.FromSeconds(10));
    Console.Write("Say your name (or q to quit): ");
    var name = Console.ReadLine();

    if (string.IsNullOrEmpty(name))
    {
        continue;
    }

    if (name == "q")
    {
        break;
    }

    var process = host.Services.GetRequiredService<IAmACommandProcessor>();
    process.Post(new Greeting { Name = name });
}

await host.StopAsync();

public class Greeting() : Event(Guid.NewGuid())
{
    public string Name { get; set; } = string.Empty;
}

public class GreetingMapper : IAmAMessageMapper<Greeting>
{
    public Message MapToMessage(Greeting request)
    {
        var header = new MessageHeader();
        header.Id = request.Id;
        header.TimeStamp = DateTime.UtcNow;
        header.Topic = "greeting.topic";
        header.MessageType = MessageType.MT_EVENT;

        var body = new MessageBody(JsonSerializer.Serialize(request));
        return new Message(header, body);
    }

    public Greeting MapToRequest(Message message)
    {
        return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
    }
}

public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandler<Greeting>
{
    public override Greeting Handle(Greeting command)
    {
        logger.LogInformation("Hello {Name}", command.Name);
        return base.Handle(command);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值