How to Simplify & Scale Inter-Role Communication Using Windows Azure Service Bus
The following blog post demonstrates how Windows Azure developers can leverage the Windows Azure Service Bus to enable asynchronous inter-role communication in cloud-based solutions using Service Bus topics and subscriptions. This post and its associated code sample offer a complete solution, one that enables simplified, scalable, loosely coupled communication between role instances on the Windows Azure platform.
Background
A few months ago, we published an article that described how useful inter-role communication can be in the Windows Azure world. The article articulated how to regain and amplify the benefits of inter-role communication by using Service Bus, and also provided guidance, such as using the Observer pattern to abstract an event-driven programming paradigm and Parallel LINQ to take advantage of multi-core computers. The original technical implementation of the inter-role communication scenario was based on the “direct” messaging pattern offered by Service Bus NetEventRelay binding.
A lot of ice cubes have melted since then. The Windows Azure AppFabric team recently released a CTP version of a set of “brokered” messaging features in Service Bus along with queues and topics, all of which make it easier for developers to build reliable, distributed, scalable, loosely coupled applications using the asynchronous messaging pattern. Queues support the one-to-one pattern in which each message is consumed by a single consumer while topics support the one-to-many pattern in which each message is consumed by one or more subscriptions that are registered with the topic. Subscriptions can use filtering to select a subset of the messages from the topic. Both queues and topics offer a rich set of capabilities, including support for correlation, sessions, large messages, duplicate detection, dead-lettering and extensible message properties.
In this post, I intend to refresh the original guidance with the implementation of the inter-role communication pattern leveraging the new publish/subscribe capability introduced in the latest release of Service Bus. The end goal is to demonstrate how Service Bus can help solve the challenges related to inter-role communication and make it easier to connect pieces of distributed solutions across deployment boundaries and geographies in a simple and scalable manner.
Real-World Customer Scenario
Consider a travel search website. Users provide basic criteria such as departure city, arrival city, dates, the number of travelers, other preferences, and the web site responds with options of airline, hotels, rental car and special deals.
The system architecture includes a web-based application with front-end logic and a user interface and some middle-tier services hosting business logic for processing search requests. In the business logic layer, there is a “Search Analytics & Result Aggregation” (SARA) service that is responsible for communicating with various back-end services and collecting intermediate results. It aggregates all responses from individual search services which deal only with a specific portion of the request – flight information, hotel details, car hire options and special deals. These services in turn communicate with LOB applications and other third-party services in order to fulfill the user requests.
A popular approach to handling the data exchange between distributed application services is to employ a loosely coupled messaging architecture. A user request with search criteria is received by the web application and is routed to the SARA service to initiate its processing. A message exchange pattern that involves sending a message to a single recipient is known as unicast. Next, the SARA service distributes a search request message to multiple back-end services, each performing search operations in their own domains: flights, hotels, car rentals, deals. In this scenario, a single message is intended to be received by multiple consumers. Such a message exchange pattern is known as multicast. When each individual search service fulfills a request, it responds back to the originating SARA service with partial search results for the specific section of the end-to-end itinerary. These responses are returned to the SARA service for the final stage of processing. Again, this is another example of unicast messaging. The SARA service collects all partial responses and composes them into a coherent result which then gets submitted back to the web tier so that it can be rendered to the user on a web page.
As a reference point, below is the visual representation of the above message flow.
![]()
As it can be seen in the above example, different pieces of the application logic run in different types of Windows Azure roles and span multiple hosted services. There are advantages to constructing an application as a collection of loosely-coupled components. Windows Azure supports this model by having distinct roles to host the different functions of the application (e.g. a Web role for presentation logic, a Worker role for middle-tier logic, etc.). The communication between the solution’s tiers and services needs to happen seamlessly across the entire deployment. A web role instance should be able to communicate to the worker role instance that is deployed in a different hosted service. By isolating the tiers of a cloud-based solution into individual hosted service deployments, one can simplify operations such as upgrading or re-configuring a specific tier without impacting other tiers that are not affected by a servicing operation.
Furthermore, for high-availability reasons, it is typical to run multiple instances within each tier of the application. In the customer scenario above, the web application and SARA service will ultimately become candidates for multi-instance deployment in order to be highly available. Such a topology imposes a requirement on the inter-role communication mechanism to support multiple role instances as “competing consumers” and ensure guaranteed delivery of messages to one and only one instance.
Extending the deployment resiliency further, and as far as disaster recovery (DR) is concerned, it is common for a fully DR-compliant solution to be deployed in different data centers. When all the role instances for a particular tier go down in one data center, a DR set of role instances running the same logic from another data center can process the message. For example, if all SARA service instances in North Central US datacenter are not available by whatever reason, the user request should be processed by a copy of the SARA service running in South Central US datacenter. Spanning data centers using traditional mechanisms for inter-role communication (e.g. external endpoints) is not straightforward; doing it securely and reliably makes it even more complicated. So, whatever other option for inter-role communication is available, it needs to seamlessly address communications across any boundaries, be that within a single datacenter or across datacenters.
And finally, in a hybrid deployment scenario, some services of a cloud-based solution may be hosted on the premises. These services require being reachable from theirs consumers while keeping a great degree of location virtualization so that consumers doesn’t have to be bound to a specific endpoint address. In the above example, the back-end services can be co-located along with the LOB applications and other systems that must stay on-premises and cannot be moved to the cloud. Such a deployment raises further requirements related to a secure communication between cloud-based and on-premises services.
In summary, these challenges lead to a need to provide a seamless way to support the inter-role communication regardless of the deployment topology. That was the original motivation behind this blog post which naturally brings us into a technical design discussion on how it can be implemented.
Technical Design Walkthrough
To follow along, download the full sample code from the MSDN Code Gallery. If you would like to skip the design discussion and jump over to the implementation details, please go to the next section.
In the previous section, our real-world customer scenario has combined multiple message exchange patterns to address a set of data flow requirements. First, there is unicast-based messaging that occurs between the web application and the Search Analytics & Aggregation service. Second, there is multicast-based message distribution which fans out a search request to a number of distributed back-end services for processing. In addition to supporting these two key message exchange patterns, a good technical design must meet the following goals:
-
Generically simple which implies a minimum setup effort and no “excessive baggage” of features except those that are required to support the inter-role communication mechanism, ideally expressed in the familiar “publish/subscribe” notion.
-
Fully abstracted to hide all the mechanical parts used in handling message exchange operations and remove client’s dependency on the underlying communication and messaging APIs.
-
Inherently reliable to make inter-role communication resilient to intermittent connectivity and contention issues that may manifest themselves in multi-tenant, congested or highly distributed environments.
-
Practically cost-efficient to decrease the operating costs related to running a solution leveraging the inter-role communication via Service Bus.
The following subsections intend to walk you through the main design concepts that I have applied in the technical implementation.
Messaging Entities
First, let me describe at a high level how Service Bus publish/subscribe messaging is plugged in into the design and implementation of the inter-role communication (or IRC for short) discussed in this post.
The key Service Bus messaging entities involved are topics, subscriptions and rules.
-
Topics support the publish/subscribe message exchange pattern in which each published message is made available to all subscriptions registered with a given topic. By contrast, in a queue each message is only consumed by a single consumer.
-
Subscriptions act like virtual queues which receive a copy of each message that is published into a topic. A subscription can have one or more rules defined to restrict the messages that it wants to receive.
-
Rules are filter expressions that are used to select which messages are “copied” in to the subscription’s virtual queue. Rules can optionally have associated filter actions that can manipulate the properties of the message as it flows in to a subscription’s virtual queue.
For more information on topics, subscriptions and rules please refer to alternative sources listed in the “Additional Resources/References” section.
Inter-Role Communication Topic
In our design, the communication between Windows Azure role instances is done through a single topic that is provisioned ahead of time. In the current CTP of Service Bus, a single topic supports up to 500 concurrent publishers and subscribers, however this limit may be re-evaluated and could change in the future. The topic name is specified in the application configuration and is assumed to always exist when a Windows Azure solution is deployed. Only those role instances that share the same topic name in their configuration will be able to communicate together.
Subscription Management
The management of subscriptions and filters is the responsibility of the component implementing the inter-role communication (further referred to as the “IRC component”). By default, subscriptions that are internally maintained by the IRC component are dynamic in nature. This means that the subscriptions are created at runtime, and are removed upon graceful termination of the host (a Windows Azure role instance process). If a role instance fails over to another node or restarted, it will be re-attached to the original subscription after a successful reboot. The IRC component can also be configured to support static subscriptions which are created once and never removed by the IRC component.
Filters & Event Routing
The inter-role communication topic has one or more subscriptions (or “IRC subscription” for short) that are created automatically at runtime with a single filter. The filter contains an expression allowing the subscription to accept messages sent either to all role instances, all instances of a particular role or a specific role instance. This is implemented as follows. Each inter-role communication event (or “IRC event” for short) is published as a message with two custom properties; these are IRC_From and IRC_To. When IRC_To is set to a predefined value of “*” (an asterisk symbol), this tells the subscribers that an event shall be treated as a multicast message and can be received by all role instances. By contrast, when IRC_To is set to a value that corresponds to an internally computed globally unique ID of a particular Windows Azure role instance, only that specific instance will receive an IRC event. In addition to that, the IRC_To property can also be set to the name of a particular role. In this scenario, either all instances of the given role will receive a copy of the message or only one instance will receive the message depending on whether the inter-role communication is configured to allow competing consumers.
In addition, each publisher can receive a copy of the IRC events it publishes. Consider it as a carbon copy feature. It can be enabled on demand should this capability be required. Carbon copies may be useful if the communication needs to occur between decoupled services or processes hosted by the same role instance node. Such a communication pattern is sometimes referred to as “intra-application communication”. In the given context, the use of Service Bus topics and their durability help make intra-application communication reliable and guaranteed. Another potential use case for a carbon copy is to enable the sender to verify that the underlying publish/subscribe infrastructure is fully operational end-to-end. A receipt of a carbon copy indicates that the message successful went through the topic and came back. However, it should not be treated as an acknowledgement as this doesn’t warrant a successful receipt by all participating subscribers.
The filter expression that defines who can and cannot receive IRC events can be visualized as follows:

The interesting part in the above filter definition is that such a simple expression can effectively accommodate both unicast (single recipient) and multicast (many recipients) message exchange patterns, and also allows filtering out carbon copies if they are not desirable.
In order to reduce the coupling between the application code and the underlying communications infrastructure, I introduced an abstraction layer implemented via a generic contract, as shown below. Here I take advantage of the IObservable<T> interface which enables pushing the IRC events to one or more observers.
/// <summary> /// Defines a generic contract for inter-role communication mechanism using publish/subscribe messaging infrastructure. /// </summary> public interface IInterRoleCommunicationExtension : IObservable<InterRoleCommunicationEvent>, IDisposable { /// <summary> /// Publishes the specified inter-role communication event to one or more subscribers. /// </summary> /// <param name="e">The inter-role communication event to be delivered to the subscribers.</param> void Publish(InterRoleCommunicationEvent e); }
It is expected that the implementations of the IInterRoleCommunicationExtension interface may possess some system resources such as communication objects that need to be explicitly disposed in a controlled manner. Therefore, the contract also supports the Dispose pattern by inheriting from IDisposable as shown above. In summary, the IInterRoleCommunicationExtension interface includes just 3 methods to be implemented: Publish, Subscribe and Dispose.

The next section provides examples of how and where to use the above methods.
Another code artifact that is worth mentioning in the context of the IRC framework is the InterRoleCommunicationEvent class which has surfaced in the inter-role communication interface above. This class implements a generic IRC event that carries user-defined payload, custom properties and event routing information. The implementation of this class is defined as follows:
/// <summary> /// Represents a generic event for inter-role communication. /// </summary> [DataContract] public class InterRoleCommunicationEvent { /// <summary> /// Returns the event payload which is a DataContract-serializable object that carries the event's body. /// </summary> [DataMember] public object Payload { get; private set; } /// <summary> /// Returns the ID of the event sender. /// </summary> [DataMember] public string From { get; internal set; } /// <summary> /// Gets or sets the ID of the event receiver. /// </summary> [DataMember] public string To { get; set; } /// <summary> /// Returns a collection of custom properties associated with the event. /// </summary> [DataMember] public IDictionary<string, object> Properties { get; private set; } }
Let’s take a look at the event message flow. The diagram below depicts the inter-role communication between three roles in a Windows Azure solution, each deployed in its own hosted service spanning two different datacenters.
In the example above, there is a single topic with 8 subscriptions. Each subscription is created by the individual role instances at startup. Inside each subscription, there is a single rule with a filter expression similar to the one discussed earlier.
Sending a message to a particular role instance (a unicast pattern) involves setting up a correct value of the IRC_To message context property. This is performed by the IRC component so that the consumer doesn’t need to worry about dealing with these low-level concepts. In the above example, a unicast message is sent from role instance S1-1 to S3-1. The message is put into a topic with IRC_To equal to “S3-1” and matched to a single subscription created by role instance S3-1. The message is then reliably delivered to its destination.
To fan out a message to multiple role instances (a multicast pattern), the IRC_To message context property is set to an asterisk symbol. When the message is put into a topic, it is matched by all active subscriptions and therefore will be delivered to all role instances listening on their subscriptions.
Those are the main aspects that you need to be conceptually aware of. In the next section, these concepts are turned into concrete guidance around enabling inter-role communication for a Window Azure solution.
On a side note, it is worth mentioning that the technical solution discussed above represents a generic framework that supports a broad range of message exchange patterns. Such a generic approach has led to a certain degree of unification and standardization of how message exchange is implemented behind the scene. If you are building a messaging solution using Service Bus to address a specific problem, there will be alternative approaches with respect to a particular problem space.
Step-By-Step Implementation Guide
Let’s proceed with a step-by-step instruction on how to enable a Windows Azure solution to support the inter-role communication mechanism discussed in this post.
Step 1: Create a Service Bus Namespace
You will first need to provision a Service Bus namespace. If you already have an existing namespace, it can be reused for inter-role communication. In either case, you will need to note down the three key elements: namespace name, issuer name and issuer secret.

The three highlighted parameters will be required for configuring the inter-role communication component in step 3.
Step 2: Add an Inter-Role Communication Component to a Window Azure Solution
In this step, you will add a reference to Microsoft.AzureCAT.Samples.InterRoleCommunication.dll assembly to every project implementing either web or worker roles in a Visual Studio solution. In addition, add a reference to Microsoft.ServiceBus.dll and Microsoft.ServiceBus.Messaging.dll from the AppFabric SDK. The location of these assemblies depends on the version of the SDK. For June CTP, the path is %ProgramFiles%Windows Azure AppFabric SDK – June 2011 CTPServiceBus.
| It is very important to set the Copy Local property of the respective assembly references to True. Otherwise, the role instances may not initialize and spin themselves off successfully when deployed on Windows Azure. |
Step 3: Configure the Inter-Role Communication Component
Once a reference to the assembly containing the IRC component has been added to the respective projects, the next step is to provide some configuration information to enable the IRC component to connect to the target Service Bus topic. Such a configuration will need to be supplied in the app.config file in each Visual Studio project implementing a web or worker role. The respective app.config file is to be modified as shown:
<configuration> <configSections> <!-- Add this line into your own app.config --> <section name="ServiceBusConfiguration" type="Microsoft.AzureCAT.Samples.InterRoleCommunication.Framework.Configuration.ServiceBusConfigurationSettings, Microsoft.AzureCAT.Samples.InterRoleCommunication" /> </configSections> <!-- Add this entire section into your own app.config --> <ServiceBusConfiguration defaultEndpoint="IRC"> <add name="IRC" serviceNamespace="irc-test" endpointType="Topic" topicName="InterRoleCommunication" issuerName="owner" issuerSecret="wjc/h98iL95XudZPJ1txaDB..." /> </ServiceBusConfiguration> </configuration>
In your version of app.config file, 3 parameters in the above fragment will have to be modified:
If required, you can also modify the name of the Service Bus topic that will be used to exchange the IRC events.
| If you have multiple Visual Studio projects implementing web/worker roles which need to participate in the inter-role communication, you will need to ensure that the app.config file is present in each project. Instead of creating multiple copies of app.config and placing them in each individual project, you can add app.config as a link rather than directly adding the file to your projects. Linked project items in Solution Explorer can be identified by the link indicator in its icon (a small arrow in the lower left corner). By linking to a file, you can capture ongoing changes to the configuration file without having to manually update a copy whenever changes are made. To create a link to a file, select the target project, open the Add Existing Item dialog box, locate and select the master app.config file you want to link. From the Open button drop-down list, select Add As Link. |
In addition to configuration settings expressed inside an app.config file, the IRC component supports several useful runtime settings that are intended to be programmatically modified if their default values are not sufficient. These runtime settings are combined in the InterRoleCommunicationSettings object and are listed below:
| Setting | Description | |
| EventTimeToLive | Specifies a custom time-to-live (TTL) value for inter-role communication events. Events older than their TTL will be removed before they can reach the subscribers. | 10 minutes |
| EventWaitTimeout | Specifies a custom time value indicating how long Service Bus messaging API will keep a communication channel open while waiting for a new event. | 30 seconds |
| EventLockDuration | Specifies a custom duration in which the inter-role communication events that are being processed remain marked as “in-flight” and invisible to other competing consumers (if any). | 5 minutes |
| EnableAsyncPublish | Enables publishing the inter-role communication events in an asynchronous, non-blocking fashion eliminating the need to wait until events are put into a topic. | False |
| EnableAsyncDispatch | Enables dispatching the inter-role communication events to their subscribers immediately as soon as a new event arrives, without waiting until the previous event is processed. | True |
| EnableParallelDispatch | Enables dispatching the inter-role communication events to multiple subscribers in parallel without serializing execution of subscribers. | True |
| EnableCarbonCopy | Enables the publishing role instances to receive their own events as carbon copies. | False |
| UseCompetingConsumers | Enables multiple role instances to receive the inter-role communication events from the same subscription with the guarantee that each event is consumed only by one of the role instances. | False |
| RetryPolicy | Specifies a retry policy that will be used for ensuring reliable access to the underlying messaging infrastructure. | Fixed Interval |
Step 4: Initialize the Inter-Role Communication Component
In this step, you will extend the startup logic of your web or worker role implementation with a code snippet that is responsible for initializing the IRC component. The following example demonstrates how to initialize the IRC component from within a worker role.
using Microsoft.AzureCAT.Samples.InterRoleCommunication; using Microsoft.AzureCAT.Samples.InterRoleCommunication.Framework.Configuration; public class SampleWorkerRole : RoleEntryPoint { private IInterRoleCommunicationExtension interRoleCommunicator; /// <summary> /// Called by Windows Azure service runtime to initialize the role instance. /// </summary> /// <returns>Return true if initialization succeeds, otherwise returns false.</returns> public override bool OnStart() { // ...There is usually some code here... try { // Read the configuration settings from app.config. var serviceBusSettings = ConfigurationManager.GetSection(ServiceBusConfigurationSettings.SectionName) as ServiceBusConfigurationSettings; // Resolve the Service Bus topic that will be used for inter-role communication. var topicEndpoint = serviceBusSettings.Endpoints.Get(serviceBusSettings.DefaultEndpoint); // Initialize the IRC component with the specified topic endpoint. // Instantiating the IRC component inside the OnStart method ensures that IRC component is a singleton. // The Singleton pattern prevents the creation of competing consumers for the same IRC events. this.interRoleCommunicator = new InterRoleCommunicationExtension(topicEndpoint); } catch (Exception ex) { // Report on the error through default logging/tracing infrastructure. Trace.TraceError(String.Join(ex.Message, Environment.NewLine, ex.StackTrace)); // Request that the current role instance is to be stopped and restarted. RoleEnvironment.RequestRecycle(); } // ...There is usually some more code here... return true; } // ...There is usually some more code here... }
In summary, you will need to add a private field of type IInterRoleCommunicationExtension which will be initialized with an instance of the IRC component using the configuration information loaded from app.config.
In web roles, the IRC component initialization logic must be placed into the Global.asax.cs file, most specifically into its Application_Start method. The Application_Start method is called only once during the lifecycle of the IIS application pool that belongs to the web role instance. Another popular approach is to implement a lazy initialization whereby the IRC component instance will only be created when it’s first accessed as shown in the example below:
public class Global : System.Web.HttpApplication { private static Lazy<IInterRoleCommunicationExtension> ircLazyLoader = new Lazy<IInterRoleCommunicationExtension>(() => { var serviceBusSettings = ConfigurationManager.GetSection(ServiceBusConfigurationSettings.SectionName) as ServiceBusConfigurationSettings; var topicEndpoint = serviceBusSettings.Endpoints.Get(serviceBusSettings.DefaultEndpoint); return new InterRoleCommunicationExtension(topicEndpoint); }, LazyThreadSafetyMode.ExecutionAndPublication); public static IInterRoleCommunicationExtension InterRoleCommunicator { get { return ircLazyLoader.Value; } } // ...There is usually some more code here... }
| It is recommended that the IRC component is not to be instantiated by a role instance more than once per single topic. Under the hood, the component maintains a messaging client with an active subscription affinitized to a particular role instance ID. Multiple instances of the IRC component created by a role instance for the same topic will share the same subscription. This will create competing consumers for the subscription and may result in inter-role communication events being consumed by incorrect instances of the IRC component. Therefore, an instance of the InterRoleCommunicationExtension class must always be a singleton for a given topic. Make sure you implement a Singleton pattern when creating an instance of this class. Note that multiple instances of the IRC component in a single role instance are allowed, provided that you initialize the IRC component instances using different topic endpoints. |
Step 5: Subscribe to Inter-Role Communication Events
In order to start receiving inter-role communication events, you will need to implement and activate a subscriber to these events. The subscriber is a class implementing the IObserver<InterRoleCommunicationEvent> interface with 3 methods: OnNext, OnCompleted and OnError. The following code is an example of the IRC event subscriber:
/// <summary> /// Implements a subscriber for inter-role communication (IRC) events. /// </summary> public class InterRoleCommunicationEventSubscriber : IObserver<InterRoleCommunicationEvent> { /// <summary> /// Receives a notification when a new inter-role communication event occurs. /// </summary> public void OnNext(InterRoleCommunicationEvent e) { // Put your custom logic here to handle an IRC event. } /// <summary> /// Gets notified that the IRC component has successfully finished notifying all observers. /// </summary> public void OnCompleted() { // Doesn't have to do anything upon completion. } /// <summary> /// Gets notified that the IRC component has experienced an error condition. /// </summary> public void OnError(Exception error) { // Report on the error through default logging/tracing infrastructure. Trace.TraceError(String.Join(error.Message, Environment.NewLine, error.StackTrace)); } }
Once a subscriber is implemented, the next step is to register it with the IRC component by letting the Subscribe method do all the heavy lifting behind the scene:
public class SampleWorkerRole : RoleEntryPoint { private IObserver<InterRoleCommunicationEvent> ircEventSubscriber; private IDisposable ircSubscription; /// <summary> /// Called by Windows Azure after the role instance has been initialized. /// This method serves as the main thread of execution for your role. /// </summary> public override void Run() { // ...There is usually some code here... // Create an instance of the component which will be receiving the IRC events. this.ircEventSubscriber = new InterRoleCommunicationEventSubscriber(); // Register the subscriber for receiving inter-role communication events. this.ircSubscription = this.interRoleCommunicator.Subscribe(this.ircEventSubscriber); // ...There is usually some more code here... } }
At this point, everything is ready to go for the very first inter-role communication event to be published. Let’s start with multicasting an IRC event to all active role instances.
Step 6: Publishing Multicast Inter-Role Communication Events
Publishing an IRC event requires creating an instance of the InterRoleCommunicationEvent class with the specified event payload, which can be either a simple .NET type or a custom DataContract-serializable object. The following fragment depicts a simplistic use case in which a string-based payload is packaged as an IRC event and published to all role instances participating in the IRC event exchange:
// Create an instance of the IRC event using a string-based payload. InterRoleCommunicationEvent e = new InterRoleCommunicationEvent("This is a test multicast event"); // Publish the event. That was easy. this.interRoleCommunicator.Publish(e);
In most cases, you will be publishing complex, strongly typed events carrying a lot more than a string. That is covered in step 8.
Step 7: Publishing Unicast Inter-Role Communication Events
To publish an IRC event that needs to be received by a specific role instance, you will need to know its role instance ID. If the target role instance resides in another hosted service deployment regardless of the datacenter location, you will also need to be in a possession of its deployment ID. To resolve the ID of a particular role instance that needs to receive an IRC event, you can query the Roles collection and walk through the list of instances for each role to find the recipient’s role instance ID.
The following code snippet is an example of how to send a unicast IRC event to the next instance succeeding the current instance in the role collection:
using System.Linq; // Find a role instance that sits next to the role instance in which the code is currently running. var targetInstance = RoleEnvironment.Roles.Where(r => { return r.Value == RoleEnvironment.CurrentRoleInstance.Role; }). SelectMany(i => i.Value.Instances). SkipWhile(instance => { return instance != RoleEnvironment.CurrentRoleInstance; }). Skip(1). FirstOrDefault(); if (targetInstance != null) { // Create an instance of the IRC event using a string-based payload. InterRoleCommunicationEvent e = new InterRoleCommunicationEvent("This is a test multicast event", roleInstanceID: targetInstance.Id); // Publish the event. That was also easy. this.interRoleCommunicator.Publish(e); }
If an IRC event needs to be received by a role instance that resides outside the current deployment – for instance, in another datacenter or in a different hosted service – you will need to resolve its deployment ID and specify it when creating the InterRoleCommunicationEvent object (see the class constructor’s signature for more details).
| The Windows Azure Managed Library defines a Role class that represents a role. The Instances property of a Role object returns a collection of RoleInstance objects, each representing an instance of the role. The collection returned by the Instances property always contains the current instance. Other role instances will be available via this collection only if you defined an internal endpoint for the role, as this internal endpoint is required for the role’s instances to be discoverable. |
Step 8: Publishing Strongly Typed Inter-Role Communication Events
As noted in step 7, most real-world scenarios for inter-role communication will involve exchanging complex events carrying a lot more than just a single piece of data. For these reasons, we have enabled you to specify an instance of any custom type as a payload for the IRC events. You will need to decorate your custom type with a DataContract attribute with every member of the type to be marked as serializable using a DataMember attribute unless certain members should not be passed through the wire. Below is an example of a custom type that can be used as an IRC event payload:
/// <summary> /// Implements an IRC event payload indicating that a new work item was put in a queue. /// </summary> [DataContract] public class CloudQueueWorkDetectedTriggerEvent { /// <summary> /// Returns the name of the storage account on which the queue is located. /// </summary> [DataMember] public string StorageAccount { get; set; } /// <summary> /// Returns a name of the queue where the payload was put. /// </summary> [DataMember] public string QueueName { get; set; } /// <summary> /// Returns a size of the queue's payload (e.g. the size of a message or the number of messages). /// </summary> [DataMember] public long PayloadSize { get; set; } }
To publish a strongly typed event, create a new InterRoleCommunicationEvent passing the instance of the custom type and then invoke the Publish method as follows:
var ircEventBody = new CloudQueueWorkDetectedTriggerEvent() { QueueName = "MyQueue" }; var ircEvent = new InterRoleCommunicationEvent(ircEventBody); this.interRoleCommunicator.Publish(ircEvent);
Strongly typed events require custom types to be shared between publishers and consumers. In other words, the respective .NET types need to be in a possession by the consumer so that it can successfully deserialize the event payload.
| The maximum size of a serialized IRC event must not exceed the maximum message size allowed by the Service Bus messaging infrastructure. As of writing, this message size limit is 256KB. To stay up-to-date with the latest limits and other important technical constraints that may apply, please visit the Windows Azure Service Bus FAQ on MSDN. |
Step 9: Dispose the Inter-Role Communication Component
The implementation of the IRC component relies on messaging APIs provided by the Service Bus. Under the hood, the component instantiates and maintains communication objects which provide access to the underlying messaging infrastructure. These objects require being disposed in a graceful and controlled manner. You will need to ensure that the IRC component is explicitly told to shut itself down by invoking its Dispose method.
The following code sample disposes the IRC component upon termination of the hosting role instance:
public class SampleWorkerRole : RoleEntryPoint { // ...There is usually some code here... /// <summary> /// Called by Windows Azure when the role instance is to be stopped. /// </summary> public override void OnStop() { if (this.interRoleCommunicator != null) { // Dispose the IRC component so that it gets a chance to gracefully clean up internal resources. this.interRoleCommunicator.Dispose(); this.interRoleCommunicator = null; } } // ...There is usually some more code here... }
The disposal of the IRC component is guaranteed not to throw any runtime exceptions; hence it’s safe to call into the Dispose method without any special precautions.
To conclude this section, it is worth mentioning that I’m going to drill down into additional examples in the upcoming days. These will include more advanced inter-role communication scenarios such as managing multiple subscribers and handling competing consumers.
Conclusion
This article showed how to build a versatile inter-role communication layer for Windows Azure solutions using new features of the Windows Azure Service Bus. In a previous post, I showed how to use the direct messaging capabilities in Service Bus to send and receive messages between role instances in an asynchronous, loosely coupled fashion. In this post, I focused on the new durable topic-based messaging offered by the latest release of Service Bus. By using the publish/subscribe architecture, you can easily get Windows Azure role instances to exchange messages and events in either one-to-one, or one-to-many compositions. The new features leveraged by our implementation of the inter-role communication bring the following benefits:
- Reduction of complexity when connecting parts of cloud-based solutions that span multiple deployments, datacenters and geographies.
- Mitigation of constraints by reducing or completely eliminating some specific drawbacks that apply to the alternative means of inter-role communication such as internal endpoints.
- Ensured durability that guarantees that messages sent between role instances will never get lost in transit.
- Better scalability allows scaling to hundreds of role instances to meet the most demanding scale-out computing requirements.
- Complete abstraction by which all the mechanics of how the underlying messaging APIs work are made totally transparent to the client.
When would you use the Windows Azure Service Bus for inter-role communication? As a point of reference, the customer scenario discussed earlier is a good summary of potential use cases. In addition, consider if the following statements can apply to your solution:
- The solution employs multiple services working in parallel. The multicast nature of the inter-role communication architecture allows many services to work concurrently on one task.
- The solution uses loosely coupled services the location of which is dynamic or fully virtualized. The service location virtualization offered by Service Bus makes it easier to deliver such an architecture.
The accompanying sample code is available for download from the MSDN Code Gallery. Please note that the source code is governed by the Microsoft Public License (Ms-PL) as explained in the corresponding legal notices.
Additional Resources/References
For more information on the topic discussed in this blog post, please refer to the following:
- ”Windows Azure Service Bus CTP User Guide” whitepaper on the Service Bus Samples site.
- “Windows Azure Service Bus CTP FAQ” article in the MSDN library.
- ”An Introduction to Service Bus Topics” post on the Windows Azure AppFabric Team blog.
- “Exploring Topics and Queues by Building a Service Bus Explorer Tool – Part 1” post on the Windows Azure CAT blog.
- “Implementing Reliable Inter-Role Communication Using Windows Azure Service Bus, Observer Pattern & Parallel LINQ” post on the AppFabric CAT blog.
Did this blog post help you? Please give us your feedback. Tell us on a scale of 1 (poor) to 5 (excellent), how would you rate this post and why have you given it this rating? For example:
- Are you rating it high due to having quality code samples, self-explanatory visuals, clear writing, or another reason?
- Are you rating it low due to poor examples, fuzzy screen shots, or unclear writing?
Your feedback will help us improve the quality of guidance we release. Thank you!
Authored by: Valery Mizonov
Contributed by: Abhishek Lal, Rama Ramani, Paolo Salvatori, David Ingham, Sidney Higa
3 Comments
Leave a Reply
You must be logged in to post a comment.














Pingback: Distributed Weekly 114 — Scott Banwart's Blog
Pingback: Implementing Reliable Inter-Role Communication Using Windows Azure Service Bus, Observer Pattern & Parallel LINQ | Windows Azure Customer Advisory Team (CAT)
Pingback: Using Service Bus to send messages from a Web Role to all other Web Roles - Windows Azure Blog