Skip to content

Per message options configuration for IMessagePublisher#341

Open
EtherZa wants to merge 4 commits into
aws:devfrom
EtherZa:feature/publish-options
Open

Per message options configuration for IMessagePublisher#341
EtherZa wants to merge 4 commits into
aws:devfrom
EtherZa:feature/publish-options

Conversation

@EtherZa

@EtherZa EtherZa commented May 13, 2026

Copy link
Copy Markdown

#340

Adds optional per-message configureOptions callbacks to IMessageBusBuilder.AddSQSPublisher and IMessageBusBuilder.AddSNSPublisher.

With this change, applications using the generic IMessagePublisher can populate SQS- and SNS-specific publish options from the message being sent. This enables scenarios such as publishing to FIFO queues and topics by deriving values like MessageGroupId and MessageDeduplicationId from the message itself, while still using type-based routing through IMessagePublisher.
The change also allows these callbacks to override service-configured defaults for a given publish operation, providing additional flexibility when message-specific behavior is required. Documentation has been updated to describe this capability in the publishing guidance.

Example usage:

builder.Services.AddAWSMessageBus(builder =>
{
    builder.AddSQSPublisher<TransactionInfo>(
        "https://sqs.us-west-2.amazonaws.com/012345678910/MyFifoQueue.fifo",
        configureOptions: (message, options) =>
        {
            options.MessageGroupId = message.TransactionId;
            options.MessageDeduplicationId = message.TransactionId;
        });

    builder.AddSNSPublisher<BidInfo>(
        "arn:aws:sns:us-west-2:012345678910:MyFifoTopic.fifo",
        configureOptions: (message, options) =>
        {
            options.MessageGroupId = message.BidId;
            options.MessageDeduplicationId = message.BidId;
        });
});

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@EtherZa EtherZa force-pushed the feature/publish-options branch from 29b7178 to 661f525 Compare May 13, 2026 06:16
@EtherZa EtherZa changed the base branch from main to dev May 13, 2026 06:20
@EtherZa EtherZa requested review from a team as code owners May 13, 2026 06:20
@EtherZa EtherZa requested review from GarrettBeatty and normj May 13, 2026 06:20

@normj normj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of this PR. I might be over thinking this but just wondering if a user might need access to the services registered in the DI container. For example use some DI service that would be able to look up the group id based on a customer id on the on the message. In that case the service call might be async so it might be good then for the callbacks to return ValueTask.

EtherZa added 3 commits May 14, 2026 07:52
- Add async, DI-enabled per-message config for SQS/SNS/EventBridge publishers via new Action/Func overloads
- MessageRoutingPublisher now resolves publishers from DI per publish (cached in DI provider)
- Register IMessagePublisher as scoped, not singleton
- Bump version to Major due to breaking API changes
@EtherZa

EtherZa commented May 14, 2026

Copy link
Copy Markdown
Author

@normj I have added per-message options configuration for publishing to the EventBridge too. It probably won't have too much real world usage, but it is opt-in and keeps expectations aligned.

IServiceProvider has been added with overloads for Action<...> and Func<..., ValueTask> (syntactic sugar to wrap Action in a Func). It has unfortunately come with some small, but breaking changes for which I have bumped the release from a minor to major (but please review and adjust accordingly).

Breaking changes:

  1. MessageRoutingPublisher (IMessagePublisher) is no longer registered as a singleton. The IServiceProvider instance needs to be scoped with the calling class so that it can be passed on to the config action/func.
  2. ServiceCollectionExtensions.AddAWSMessageBus was exposing MessageBusBuilder instead of the interface. I suspect that it was an oversight and has been changed to keep the overloads in the interface where possible. If you would like to avoid this change, the overloads can be moved to the MessageBusBuilder class.

These are both technically breaking changes, but may not warrant a full bump.

builder.Services.AddAWSMessageBus(builder =>
{
    // synchronous
    builder.AddSQSPublisher<TransactionInfo>(
        "https://sqs.us-west-2.amazonaws.com/012345678910/MyFifoQueue.fifo",
        configureOptions: (serviceProvider, message, options) =>
        {
            options.MessageGroupId = message.TransactionId;
            options.MessageDeduplicationId = message.TransactionId;
        });

    // asynchronous
    builder.AddSNSPublisher<BidInfo>(
        "arn:aws:sns:us-west-2:012345678910:MyFifoTopic.fifo",
        configureOptions: async (serviceProvider, message, options, cancellationToken) =>
        {
            var service =  serviceProvider.GetRequiredService<SomeService>();
            var messageGroupId = service.GetMessageGroupIdAsync(message, cancellationToken0;

            options.MessageGroupId = messageGroupId;
        });
});

I have left each commit unsquashed to make rollback, etc easier. Please modify/drop as you see fit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants