There are many scenarios where you will need to do interrole communication when creating a solution using Windows Azure platform such as multiple web roles that need to recycle when a controller triggers an event.
One way to achieve this goal is to create an event queue, modify the controller to enqueue a message that indicates a recycle is requested and make your web roles listen to this queue. Your controller can also enqueue 3 messages if you have 3 Web Roles to recycle. Below is the basic design for such an approach.
While you can use a queue as to mediate your messaging needs, you can also use WCF services to do interrole communication. In this approach, your roles would expose an internal endpoint, bind a WCF service that would listen on this endpoint. Your controller would use the RoleEnvironment to identify each role instance and invoke the service endpoints to notify each instance that a recycle is required. The design for this approach is below.
In this post I will try to provide a simple example of interrole communication using WCF – in other words, I will try to realize the design above. The code examples will not have much error handling, instead I will try to concentrate on the basics. Our Tier 1 Role Instances will expose a WCF Service that will use TCP transportation. The service interface will be a simple one that will include a one-way function called RecycleYourself. Upon retrieval of this message, our Tier 1 Role instances will recycle themselves.
We will start with adding input endpoints for our Tier 1 Role instances. This is pretty easy to do using Visual Studio. We will start with right clicking on the Worker Role definition and selecting properties.
In the endpoints section of the Tier 1 Worker Role properties screen, we will click on the “Add Endpoint” button to add a new internal endpoint. Let’s name it “NotificationServiceEndPoint”, select “Internal” as the type (we are selecting the “Internal Endpoint Type” since we will not be exposing this endpoint to external world) and select Protocol to be TCP.
Next step is to create an interface for the service that will accept the recycle notification. This interface will expose a one-way endpoint. You can modify the contracts to suit your needs. I would suggest creating a class library project and putting the contracts in this project since we will be referencing it both for hosting and consumption purposes. The project that you create for your service and contracts should reference System.Servicemodel and System.Runtime.Serialization assemblies.
The code for the datacontract is provided below. This will be our message that is passed as a parameter to the host.
The service contract is a very simple one. The only function will be a void one called RecycleYourself with a parameter of type NotificationMessage.
Next step is to host a WCF Service in our Tier 1 Worker Roles. This service host will expose an event that will be raised whenever our service receives a notification message. We will later handle that event in our Worker Role and take appropriate actions. The hosting code is provided below.
As you can see in the code snippet above, we are taking an event driven approach. Our service host exposes an event called RecycleNotificationRecieved. Whenever we receive a RecycleYourself call, we raise this event. We will handle this event in our Worker role and take the appropriate actions once this event is received.
There are also some attributes in our service host and one of them is very important for our case. We will only need one instance of this service in our Worker role and we want to use it throughout the lifecycle of our Worker role instance. To achieve this goal, we have set the InstanceContextMode in the service to InstanceContextMode.Single.
In order to host this service in our Tier 1 worker role, we will first reference to the project where we have created our interfaces. We will later need to get the endpoint that we created above, create an instance of our host and instantiate a service host around this instance. We will also hook into the event and handle it in our worker role. We will create and run the service in our Run() method. Below is the full listing of our Tier 1 worker role.
As our Tier 1 instance is ready to host our service, now is the time to modify our controller. We will call our controller worker role, Tier 2 worker role. In this worker role, we will create a proxy for our service, find out all instances of Tier 1 Role, get their service endpoints and invoke the appropriate endpoints. The code for this process is below.
As you can see above, the NotifyRolesForRecycle is the function where we do most of the work. In this function we get the role for “Tier 1 Worker Role” using the RoleEnvironment.Roles dictionary. Once we get the Role object, we iterate through its instances. For each instance we get the endpoint using InstanceEndPoints dictionary of RoleInstance object. After creating a basic TCP binding and an endpoint to use with our channel factory, we create a client and invoke the RecycleYourself function.
Allow me to underline that the example I have provided above lacks error handling, tracing and any other decorations to make it robust. Again, for example purposes I tried to keep the interfaces simple. You can enhance this example to use more complex data contracts, add more functionality to your services. You can also use Duplex Bindings which will be very handy if you need check the status of other worker roles.
Written by Hakan Onur