Publish/Subscribe on Azure with NServiceBus

The Pattern

The Pub/Sub (or Publish/Subscribe) pattern is a loosely coupled messaging pattern between different components in a system. Certain components, the subscribers, show their interest in certain messages by adding their endpoint to a list of subscriptions for those messages. The publishers will consult this list of subscriptions and send the message to every endpoint subscribed to the message.

This pattern is one of the many messaging patterns that are supported by the NServiceBus framework, and of course I added support to it for using this pattern on Azure as well, using table storage or sql azure. If you want more information on how NServiceBus supports Pub/Sub read the following article: http://www.nservicebus.com/PubSub.aspx

Configuring NServiceBus for Pub/Sub on Azure

Setting up NServiceBus to store the subscription list on azure table storage can be done by simply adding a configuration setting to the role’s configuration file that defines the connection string. This connection string has to follow the format defined by Microsoft at http://msdn.microsoft.com/en-us/library/ee758697.aspx.

<Setting name="AzureSubscriptionStorageConfig.ConnectionString"
        value="UseDevelopmentStorage=true" />

Besides adding the connection string, you also need to call the AzureSubscriptionStorage configuration method when configuring your bus.

Bus = Configure.With()
            .DefaultBuilder()
            .Log4Net(new AzureAppender())
            .AzureConfigurationSource()
            .AzureMessageQueue()
                .JsonSerializer()
            .AzureSubcriptionStorage()
            .UnicastBus()
                .LoadMessageHandlers()
                .IsTransactional(true)
            .CreateBus()
            .Start();

Configuring the Azure Host

As an alternative to manually configuring the bus in a worker role, you can also use the RoleEntryPoint defined in the NServiceBus.Hosting.Azure assembly. You need to inherit from this class so that the azure startup conventions can detect your entrypoint.

public class Host : RoleEntryPoint{}

The host takes a number of marker interfaces into account when starting the bus, such as AsA_Worker for example. This marker interface will ensure the setup of the azure subscription storage as well as saga storage, just don’t forget to include the configuration setting in you’re roles configuration file otherwise it will default to using the development storage emulator.

public class EndpointConfiguration : IConfigureThisEndpoint, AsA_Worker { }

As mentioned, we support more than 1 store for state information azure table storage and sql azure. This can be controlled by using profiles, in this case I’ve set the profile to

NServiceBus.Production NServiceBus.OnAzureTableStorage NServiceBus.WithAzureStorageQueues

The Pub/Sub Sample

The NServiceBus sources contain a sample that demonstrates the pub/sub messaging pattern on Windows Azure. It contains a web role that submits an order to a worker role for approval.

protected void btnSubmit_Click(object sender, EventArgs e)
{
    var order = new Order
                    {
                        Id = Guid.NewGuid(),
                        Quantity = Convert.ToInt32(txtQuatity.Text),
                        Status = OrderStatus.Pending

                    };

    Global.Bus.Send(new OrderMessage
                        {
                            Id = order.Id,
                            Quantity = order.Quantity
                        });

    lock (Global.Orders)
        Global.Orders.Add(order);

    Refresh();
}

Once the order has been submitted it will listen for the approval (or denial) by subscribing to the OrderUpdatedEvent, which is handled by the following message handler for the event.

public class OrderUpdatedEventHandler : IHandleMessages<OrderUpdatedEvent>
{
    public void Handle(OrderUpdatedEvent message)
    {
        var order = message.UpdatedOrder;

        lock (Global.Orders)
        {
            if (Global.Orders.Contains(order))
                Global.Orders.Remove(order);

            Global.Orders.Add(order);
        }
    }
}

The worker role will handle the submission of the order, approve it, and publish the order updated event. Using the Publish method on the bus will make sure that the message is send to every subscriber and not just to one of the web roles.

public void Handle(OrderMessage message)
{
    var order = new Order
                    {
                        Id = message.Id,
                        Quantity = message.Quantity
                    };

    //simlute business logic
    order.Status = message.Quantity < 100 ? OrderStatus.Approved : OrderStatus.AwaitingApproval;

    //publish update
    var orderUpdatedEvent = bus.CreateInstance(x=>x.UpdatedOrder = order);
    bus.Publish(orderUpdatedEvent);
}

Now it’s up to you…

Pub/Sub is probably one of the most important messaging patterns for doing development on windows azure, as it allows you to send events to all instances of a web or worker role, enabling really interesting use cases (from cache invalidation to complete event driven architectures). Therefore I advise you to get the latest version of NServiceBus from github, https://github.com/NServiceBus/NServiceBus, and get started with the Pub/Sub sample.

Windows Azure MVP

Quite unexpectedly, when browsing my mail over the weekend, I learned that I’ve been awarded as MVP for Windows Azure by Microsoft 🙂 This recognition of all my community work makes me extremely happy, thanks to all who have voted for me!