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.

Advertisements

7 Responses to Publish/Subscribe on Azure with NServiceBus

  1. Bert Craven says:

    Hi Yves, can you confirm if the .AzureMessageQueue() is using a Service Bus Message Queue, Message Buffer or Windows Azure Queue ?

    Thanks.

  2. Bert,

    .AzureMessageQueue uses Windows Azure Storage Queues
    .ServiceBusMessageQueue uses Service Bus Message Queues

    there is no support for message buffers…

    Kind regards,
    Yves

  3. emipasat says:

    Hi Yves, in NSB 3.0 rc2 is it possible to just put a message in a queue (without using bus.Send or bus.Publish) and having an Azure worker host to pick it and deserialize it?
    I tried and I always got serialization exception, even if I used same json library to encode the message. The message is put in queue, is picked up but not handled by the message handler.

    I’m thinking at a WP7 client, that’s why I don’t have the bus available.
    Thanks in advance

  4. emipasat says:

    correction: serialization exception is thrown at pick up time, not when putting message to queue.

  5. Mike Zandin says:

    If a subscription on a topic gets deleted – say through [ServiceBus.DeleteSubscription(subscription.TopicPath, subscription.Name)] the underlying code needs to resubscribe. What is the best way to ensure that this happens?

    • Mike, NSB has it’s own subscription management features which are unrelated to that of the azure servicebus, in fact only queues are currently supported.

      If you want to unsubscribe n NSB you can use the unsubscribe method on the IBus interface.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: