DEV Community

Cover image for Migrating to Brighter V10 with RabbitMQ
Rafael Andrade
Rafael Andrade

Posted on

Migrating to Brighter V10 with RabbitMQ

In previous articles, I covered Brighter integration with RabbitMQ and Brighter V10 RC1. This guide focuses on migrating to Brighter V10, emphasizing RabbitMQ configuration changes and breaking updates.

Requirement

Brighter Recap

Before continuing about RabbitMQ configuration, let's recap what we already know about Brighter.

Request (Command/Event)

Define messages using IRequest:

public class Greeting() : Event(Guid.NewGuid())
{
    public string Name { get; set; } = string.Empty;
}
Enter fullscreen mode Exit fullscreen mode
  • Commands: Single-recipient operations (e.g., SendEmail).
  • Events: Broadcast notifications (e.g., OrderShipped).

Message Mapper (Optional)

Translates between Brighter messages and your app objects:

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; }
}
Enter fullscreen mode Exit fullscreen mode

V10 Change: Async mappers now require IAmAMessageMapperAsync

Request Handler

Processes incoming messages:

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

Configuring Brighter with RabbitMQ

1. Choosing Sync vs. Async

  • Sync (RMQ.Sync) : Uses RabbitMQ.Client V6 (blocking API). Suitable for gradual migrations.
  • Async (RMQ.Async) : Uses RabbitMQ.Client V7 (fully async API). Recommended for new projects

Tip: Migrate to Brighter V10 first, then switch to RMQ.Async to isolate changes.

2. Connection Setup

Define RabbitMQ connection details:

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

3. RabbitMQ Subscription

Subscribe to a queue/topic:

 .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));
})
Enter fullscreen mode Exit fullscreen mode

4. RabbitMQ Producer Configuration

Publish events to a topic:

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

Breaking Changes in Brighter V10

Brighter V10 introduces significant updates to RabbitMQ integration, primarily driven by the adoption of RabbitMQ.Client V6/V7 and improved async/sync separation. Below are the key breaking changes:

Package rename

To align with RabbitMQ.Client versioning and clarify async/sync usage:

  • Old: Paramore.Brighter.MessagingGateway.RMQ
  • New:
    • Paramore.Brighter.MessagingGateway.RMQ.Sync (V6 sync API)
    • Paramore.Brighter.MessagingGateway.RMQ.Async (V7 async API)

Why? RabbitMQ.Client V7 introduced breaking changes requiring code-level adjustments. The split ensures explicit compatibility and avoids runtime surprises.

Message Mapper Overhaul

Default JSON Serialization :

In V9, message mappers were mandatory. In V10, JSON serialization is built-in unless custom logic is required.

Interface Split

  • IAmAMessageMapper (sync/reactor): For synchronous workflows.
  • IAmAMessageMapperAsync (async/proactor): For asynchronous workflows.

Changes on the IAmAMessageMapper

// V10
IRequestContext? Context { get; set; }
Message MapToMessage(Greeting request, Publication publication);

// V9
Message MapToMessage(Greeting request);
Enter fullscreen mode Exit fullscreen mode

Subscription

We had 2 main changes on subscription.

Explicit Message Pump Types

The first one is before we had a field called runAsync or isAsync it was a boolean, to make everything clear we change it to messagePumpType and it's the MessagePumpType(Reactor, Proactor, Unknown).

Property Renaming

On the AddServiceActivator where rename the ChannelFactory property to DefaultChannelFactory

Publication

Here we also have 2 main changes

Configuration Overhaul

Removed IAmAProducerRegistry. Use ExternalBusConfiguration to configure producers and outbox patterns:

// V10
.UseExternalBus(opt => { ... })

// V9
.UseExternalBus(new RmqProducerRegistryFactory(...))
Enter fullscreen mode Exit fullscreen mode

Request Type Specification

The other change was about the Publication, you must setup an the request type or change the default IAmAPublicationFinder by UsePublicationFinder:

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)
}
Enter fullscreen mode Exit fullscreen mode

Migration Tips

  • Start with RMQ.Sync: Migrate to Brighter V10 first using RabbitMQ.Client V6 before adopting the async V7 package.
  • Audit Mappers: Replace IAmAMessageMapper with IAmAMessageMapperAsync for async workflows.
  • Validate Subscriptions: Ensure messagePumpType matches your async/sync requirements.
  • Update Publications: Add RequestType to non-generic RmqPublication instances or set a `IAmAPublicationFinder.

Conclusion

Brighter V10 simplifies RabbitMQ integration with clearer async/sync separation and reduced boilerplate. Key steps include:

  • Updating NuGet packages
  • Refactoring message mappers to async patterns

Top comments (0)