NServiceBus on AWS SNS: Learn How To Publish and Subscribe to Events
Let's explore how to publish Events using NServiceBus. We will learn how to Publish Events with NServiceBus, subscribe to Events and how it works under the hood when using AWS SQS Transport.
Table of Contents
This article is sponsored by AWS and is part of my AWS Series.
NServiceBus is a messaging framework that makes it easy to send, process, and publish messages across various on-premise and cloud-based queuing technologies.
In an earlier blog post, we learned how to quickly start with NServiceBus on AWS SQS. We learned how to Install and set up NServiceBus, set up the receiver and sender to listen to messages on Amazon SQS Transport, and communicate between the two using Commands.
In this blog post, let's explore how to publish Events using NServiceBus.
We will learn how to
- Publish Events with NServiceBus
- Subscribing to Events with NServiceBus
- How it works under the hood
Publish Events with NServiceBus
An Event is another type of message published to multiple receivers, unlike a Command sent to one receiver.
Events indicate an action that has happened.
To mark a message as an Event in NServiceBus, it must implement the IEvent
interface.
Following up with the same code example from our getting started blog, we can raise a UserCreatedEvent
inside our CreateUserCommandHandler
every time a user is successfully created.
public class UserCreatedEvent : IEvent
{
public Guid UserId { get; set; }
public DateTimeOffset CreatedDateTime { get; set; }
public UserCreatedEvent(Guid userId, DateTimeOffset createdDateTime)
{
UserId = userId;
CreatedDateTime = createdDateTime;
}
}
A user created indicates an action that has happened and can be used to notify other applications interested in it.
The NServiceBus message handler context IMessageHandlerContext
has a Publish
method to publish Events.
Let's update the CreateUserCommandHandler
to publish the new Event once the work is done to create a new user.
public async Task Handle(
CreateUserCommand message, IMessageHandlerContext context)
{
log.Info($"Processed message for user with Id {message.Id}, and {message.Name}");
// Create the user
// Save To database/persistent store
await context
.Publish(new UserCreatedEvent(message.Id, DateTimeOffset.UtcNow);
}
Subscribing to Events with NServiceBus
Other applications that are interested in the Events published can subscribe to them.
In NServiceBus, this is done by creating a class and implementing the IHandleMessages
interface.
Below is an example in the payroll-service
application, which is interested in the UserCreatedEvent
.
internal class UserCreatedHandler : IHandleMessages<UserCreatedEvent>
{
static ILog log = LogManager.GetLogger<UserCreatedHandler>();
public Task Handle(UserCreatedEvent message, IMessageHandlerContext context)
{
log.Info($"Payroll Service User created handler for User Id {message.UserId}");
// handle appropriate for payroll service
return Task.CompletedTask;
}
}
Any time a User is created, the payroll application has to set up new accounts for the User. You can handle this in the associated handler in the payroll application code.
Setting Up NServiceBus Event Handler on AWS SQS Transport
The Startup code for payroll-service
is very similar to how we set up the Receiver endpoints on Amazon SQS Transport.
It sets up a new Endpoint by specifying EndpointConfiguration
and configuring the transport. The Endpoint is named "payroll-service" and uses Amazon SQS as its underlying transport.
Even though the transport is named SqsTransport
, it also uses Amazon SNS under the hood, which will see later below.
using NServiceBus;
Console.WriteLine("Hello, World!");
var endpointConfiguration = new EndpointConfiguration("payroll-service");
var transport = endpointConfiguration.UseTransport<SqsTransport>();
transport.S3(bucketForLargeMessages: "user-service-large-messages", keyPrefix: "user");
endpointConfiguration.EnableInstallers();
var endointInstance = await Endpoint.Start(endpointConfiguration);
Console.WriteLine("Press any key to stop");
Console.ReadKey();
await endointInstance.Stop();
If other applications are interested in the same Events, you can add additional handlers for the same Event in those applications as well.
For example, the TaskForce/HR department might also be interested in the UserCreatedEvent
. Add a new handler in the appropriate application code as required.
Any time the UserCreatedEvent
is raised, these handlers are called independent of each other. This allows decoupling of the logic of the User being created and the associated side effects that must happen.
NServiceBus Events on AWS - Under The Hood
NServiceBus uses a combination of Amazon SNS and SQS to deliver Events to multiple subscribers.
Amazon Simple Notification Service (SNS) is a publish-subscribe service managed by AWS. It enables asynchronous communication between the publishers and subscribers using messages.
An SNS Topic is automatically created for the Event by NServiceBus and adds a subscription to the SQS Queue that the service listens on.
Any time an Event is published to the SNS Topic, it sends a copy to the SQS Queue.
In this case, we have an SNS Topic created with the name user_messages-UserCreatedEvent
. It also creates a queue for the task-force-service
, and a Subscription is added to the SNS queue.
When the UserCreatedEvent
message is forwarded to the task-force-service
SQS Queue, NServiceBus hands off the message to the Event handler for that application/Endpoint.
When you add more subscribers to the same Event, it adds more Subscriptions to the SNS and delivers a copy of the Event message to all the subscribers.
Even if the individual applications handling the Event messages are not up and running, a copy of the message is delivered to the Queue. When the application is back up and running, it can process the Events and execute the associated handler functions.
If you want to learn more about decoupling applications using SNS -> SQS, you can check out the blog post below, which I cover in full detail.
Large Event Message Sizes
It's generally recommended to keep the Event data short. Including properties that do not often change, like identifiers, date & time, URLs, etc., helps to notify relevant information while keeping the size small.
However, in cases where you need to pass larger sizes, we can use the Amazon S3 storage to offload the actual message and pass around the S3 Object URL in the Event data.
In the previous post, we saw how to configure this when dealing with large Message Sizes with NServiceBus and SQS Transport.
Full source code sample available here.
Rahul Nath Newsletter
Join the newsletter to receive the latest updates in your inbox.