Brighter V10 与 RabbitMQ 迁移指南

在之前的文章中,我已介绍了 Brighter 与 RabbitMQ 的集成。本文聚焦于迁移到 Brighter V10 的关键步骤,重点说明 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, Publication publication)
    {
        var header = new MessageHeader
        {
            MessageId = request.Id,
            TimeStamp = DateTimeOffset.UtcNow,
            Topic = publication.Topic!,
            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 IRequestContext? Context { get; set; }
}

V10 变更:异步映射器需实现 IAmAMessageMapperAsync

请求处理器

处理入站消息:

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

配置 Brighter 与 RabbitMQ

1. 选择同步 vs 异步

  • 同步 (RMQ.Sync):使用 RabbitMQ.Client V6(阻塞式 API),适合渐进式迁移。
  • 异步 (RMQ.Async):使用 RabbitMQ.Client V7(全异步 API),推荐用于新项目。

提示:先迁移到 Brighter V10,再切换到 RMQ.Async 以隔离变更。

2. 连接配置

定义 RabbitMQ 连接信息:

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

3. RabbitMQ 订阅

订阅队列/主题:

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

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

4. RabbitMQ 生产者配置

发布事件到主题:

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

Brighter V10 破坏性变更

包名变更

为适配 RabbitMQ.Client 版本并明确同步/异步用法:

  • 旧:Paramore.Brighter.MessagingGateway.RMQ
  • 新:
    • Paramore.Brighter.MessagingGateway.RMQ.Sync(V6 同步 API
    • Paramore.Brighter.MessagingGateway.RMQ.Async(V7 异步 API)

消息映射器重构

  • 默认 JSON 序列化:V10 移除强制自定义映射器。
  • 接口拆分
    • IAmAMessageMapper(同步/Reactor)
    • IAmAMessageMapperAsync(异步/Proactor)
// V10
IRequestContext? Context { get; set; }
Message MapToMessage(Greeting request, Publication publication);

// V9
Message MapToMessage(Greeting request);

订阅配置变更

  • 显式消息泵类型runAsync 改为 messagePumpType(枚举:Reactor, Proactor)。
  • 属性重命名ChannelFactory 改为 DefaultChannelFactory

发布配置变更

  • 配置重构:移除 IAmAProducerRegistry,改用 UseExternalBus 配置生产者。
// V10
.UseExternalBus(opt => { ... })

// V9
.UseExternalBus(new RmqProducerRegistryFactory(...))
  • 请求类型指定:非泛型 RmqPublication 需设置 RequestType
new RmqPublication<Greeting>
{
    MakeChannels = OnMissingChannel.Create,
    Topic = new RoutingKey("greeting.topic"),
}

// or
new RmqPublication
{
    MakeChannels = OnMissingChannel.Create,
    Topic = new RoutingKey("greeting.topic"),
    RequestType = typeof(Greeting)
}

迁移建议

1. 优先使用 RMQ.Sync:先完成 Brighter V10 迁移,再升级到 RMQ.Async。
2. 审计映射器:异步工作流需替换为 IAmAMessageMapperAsync
3. 验证订阅配置:确保 messagePumpType 匹配同步/异步需求。
4. 更新发布配置:为非泛型 RmqPublication 添加 RequestType

总结

Brighter V10 通过清晰的同步/异步分离简化了 RabbitMQ 集成,关键步骤包括:

  • 更新 NuGet 包
  • 重构消息映射器至异步模式

https://github.com/lillo42/brighter-sample/tree/v10-connect-to-rabbitmq-async

https://github.com/lillo42/brighter-sample/tree/v10-connect-to-rabbitmq-sync

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.Async;
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,
                            messagePumpType: MessagePumpType.Reactor
                        ),
                    ];

                    opt.DefaultChannelFactory = new ChannelFactory(new RmqMessageConsumerFactory(connection));
                })
                .AutoFromAssemblies()
                .UseExternalBus(opt =>
                    {
                        opt.ProducerRegistry = new RmqProducerRegistryFactory(
                            connection, [
                                new RmqPublication<Greeting>
                                {
                                    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() : Command(Guid.NewGuid())
{
    public string Name { get; set; } = string.Empty;
}

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、付费专栏及课程。

余额充值