Brighter and AWS: How to setup and use Brighter with AWS SNS/SQS

In this article, we’ll focus on integrating Brighter with AWS SNS/SQS. Introduction to AWS SNS/SQS AWS SNS (Simple Notification Service) and SQS (Simple Queue Service) form a powerful messaging backbone for distributed systems. SNS enables pub/sub messaging (fan-out to multiple consumers), while SQS provides queue-based message buffering for reliable processing. Combining these services with Brighter —a .NET library for command/query handling and messaging—allows you to build resilient, decoupled systems at scale. This guide walks through configuring Brighter to publish events via SNS and consume them via SQS, with practical code examples and workarounds for current limitations. Requirement .NET 8 or superior A .NET project with these NuGet packages Paramore.Brighter.MessagingGateway.AWSSQS: Enables AWS SNS/SQS integration. Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection: Bridge Brighter with AWS messaging services. Paramore.Brighter.ServiceActivator.Extensions.Hosting: Hosts Brighter as a background service. Serilog.AspNetCore: For structured logging (optional but recommended). Brighter Recap Before continuing about AWS SNS/SQS 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; } Commands: Single-recipient operations (e.g., SendEmail). Events: Broadcast notifications (e.g., OrderShipped). Message Mapper Translates between Brighter messages and your app objects: public class GreetingMapper : IAmAMessageMapper { public Message MapToMessage(Greeting request) { var header = new MessageHeader(); header.Id = request.Id; header.TimeStamp = DateTime.UtcNow; header.Topic = "greeting.topic"; // The target topic to be publish 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(message.Body.Bytes)!; } } Request Handler Processes incoming messages: public class GreetingHandler(ILogger logger) : RequestHandler { public override Greeting Handle(Greeting command) { logger.LogInformation("Hello {Name}", command.Name); return base.Handle(command); } } Configuring Brighter with AWS SNS/SQS Define connection settings: var connection = new AWSMessagingGatewayConnection( FallbackCredentialsFactory.GetCredentials(), // The AWS credentials AWSConfigs.RegionEndpoint, // e.g., RegionEndpoint.USWest2 opt => { // Customize AWS client settings }); SQS Consumer Configuration Subscribe to an SQS queue and map it to an SNS topic: .AddServiceActivator(opt => { opt.Subscriptions = [ new SqsSubscription( new SubscriptionName("greeting-subscription"), // Optional: For logging new ChannelName("greeting-queue"), // SQS queue name new RoutingKey("greeting.topic").ToValidSNSTopicName(), // SNS Topic Name bufferSize: 2 // Number of concurrent messages to process ) ]; opt.ChannelFactory = new ChannelFactory(connection); }) SNS Producer Configuration Publish events to SNS: .UseExternalBus(new SnsProducerRegistryFactory(connection, new [] { new SnsPublication { Topic = new RoutingKey("greeting.topic".ToValidSNSTopicName()), MakeChannels = OnMissingChannel.Create } }).Create()); Known Limitations (Brighter v9) Mandatory SNS Dependency: All messages must route through SNS—even for direct SQS use cases. No FIFO Support: FIFO queues/topics (for ordered processing) are unsupported in v9. LocalStack Compatibility Issues: Custom AWS client configurations (e.g., LocalStack endpoints) may not propagate to all internal Brighter components Good News: Brighter v10 (in development) will resolve these issues Best Practices Validate SNS Topic Name Always use .ToValidSNSTopicName() when specifying SNS topics. This Brighter helper method ensures compliance with AWS naming rules (e.g., alphanumeric characters, hyphens, and periods only). new RoutingKey("greeting.topic".ToValidSNSTopicName()) // Converts to a valid SNS topic name Configure Dead Letter Queues (DLQs) Improve fault tolerance by setting up a DLQ for failed messages. Use the redrivePolicy parameter in SqsSubscription to specify: DLQ Name: The name of the SQS queue to hold failed messages. Max Receive Count: Number of retries before messages are moved to the DLQ. new SqsSubscription( subscriptionName: new Subs

Apr 15, 2025 - 09:23
 0
Brighter and AWS: How to setup and use Brighter with AWS SNS/SQS

In this article, we’ll focus on integrating Brighter with AWS SNS/SQS.

Introduction to AWS SNS/SQS

AWS SNS (Simple Notification Service) and SQS (Simple Queue Service) form a powerful messaging backbone for distributed systems. SNS enables pub/sub messaging (fan-out to multiple consumers), while SQS provides queue-based message buffering for reliable processing. Combining these services with Brighter —a .NET library for command/query handling and messaging—allows you to build resilient, decoupled systems at scale.

This guide walks through configuring Brighter to publish events via SNS and consume them via SQS, with practical code examples and workarounds for current limitations.

Requirement

Brighter Recap

Before continuing about AWS SNS/SQS 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;
}
  • Commands: Single-recipient operations (e.g., SendEmail).
  • Events: Broadcast notifications (e.g., OrderShipped).

Message Mapper

Translates between Brighter messages and your app objects:

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"; // The target topic to be publish
        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)!;
    }
}

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);
    }
}

Configuring Brighter with AWS SNS/SQS

Define connection settings:

var connection = new AWSMessagingGatewayConnection(
 FallbackCredentialsFactory.GetCredentials(), // The AWS credentials
AWSConfigs.RegionEndpoint,  // e.g., RegionEndpoint.USWest2
opt => {  // Customize AWS client settings });

SQS Consumer Configuration

Subscribe to an SQS queue and map it to an SNS topic:

 .AddServiceActivator(opt =>
 {
      opt.Subscriptions = [
                    new SqsSubscription<Greeting>(
                        new SubscriptionName("greeting-subscription"), // Optional: For logging
                        new ChannelName("greeting-queue"), // SQS queue name
                        new RoutingKey("greeting.topic").ToValidSNSTopicName(), // SNS Topic Name
                        bufferSize: 2 // Number of concurrent messages to process
 )
                ];
                opt.ChannelFactory = new ChannelFactory(connection);
})

SNS Producer Configuration

Publish events to SNS:

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

Known Limitations (Brighter v9)

  1. Mandatory SNS Dependency: All messages must route through SNS—even for direct SQS use cases.
  2. No FIFO Support: FIFO queues/topics (for ordered processing) are unsupported in v9.
  3. LocalStack Compatibility Issues: Custom AWS client configurations (e.g., LocalStack endpoints) may not propagate to all internal Brighter components

Good News: Brighter v10 (in development) will resolve these issues

Best Practices

Validate SNS Topic Name

Always use .ToValidSNSTopicName() when specifying SNS topics. This Brighter helper method ensures compliance with AWS naming rules (e.g., alphanumeric characters, hyphens, and periods only).

new RoutingKey("greeting.topic".ToValidSNSTopicName()) // Converts to a valid SNS topic name

Configure Dead Letter Queues (DLQs)

Improve fault tolerance by setting up a DLQ for failed messages. Use the redrivePolicy parameter in SqsSubscription to specify:

  • DLQ Name: The name of the SQS queue to hold failed messages.
  • Max Receive Count: Number of retries before messages are moved to the DLQ.
new SqsSubscription<Greeting>(
    subscriptionName: new SubscriptionName("greeting-subscription"),
    channelName: new ChannelName("greeting-queue"),
    routingKey: new RoutingKey("greeting.topic").ToValidSNSTopicName(),
    bufferSize: 2,
    redrivePolicy: new RedrivePolicy(
        deadLetterQueueName: "greeting-dead", // DLQ name
        maxReceiveCount: 3 // Retry threshold
    )
)

Conclusion

Integrating Brighter with AWS SNS/SQS combines the simplicity of the Brighter library with AWS’s scalable messaging infrastructure. While v9 has limitations, its core features enable:

  • Decoupled Architecture: Producers and consumers evolve independently.
  • Resilience: SQS buffers messages during traffic spikes.
  • Scalability: SNS/SQS auto-scales to handle workloads

Reference
Full code: GitHub Repository