Register
Friday, March 19, 2010
 
 DBAs And ProgrammersBlog
  
News! Minimize
   
 
 Print   
 
Misc Blog Stuff Minimize
   
 
 Print   
 
The Reluctant DBA Minimize
 
 
 
 Print   
 
Reluctant DBA Minimize
   
 
  
 
Reluctant DBA Minimize
   
 
  
 
The Reluctant DBA Minimize
 
Jun18

Written by:CarpDeus
6/18/2009 7:27 AM 

In my last post, A REST-ful Look at Azure (Part 8) Azure Hosted Services, I took a very brief look at the Web Role and a more in-depth look at the Worker Role. Today I'm going to explore some things you should do when implementing a Worker Role.

As I said in my last post, the Worker Role should be an extremely light wrapper that calls a class that does all of the real work. There are two good reasons for this. First, the less code in the Worker Role, the less debugging you need to do in the Development Fabric, the easier it will be to write, test and debug your code. Second, the code in the Worker Role should be fairly stable. If all it is doing is instantiating a class and calling it every few seconds, it lessens the chances of errors happening in the Cloud version that will require major changes. Follow the basic rule of Keep It Super Simple when it comes to your Worker Role.

The class that the Worker Role is instantiating should include a call back function (see my blog post Services, Worker Classes and Templates, Oh My from February 23, 2009 for more details) that serves two purposes. First, it allows the Worker Role to log information to the Cloud Logs but it also updates the DateTime value the Worker Role uses to determine it's not hung. Finally, it should also include a way for the Worker Role to notify it that a request has been made to stop processing.

My generic Processing Class simply queries Azure Queue Storage to see if there is a message to be processed. There may be more than one, but the Processing Class gets just one and processes it. When it has finished, it checks to see whether or not the boolean value stopProcessing is true. If it isn't, then it checks the queue for another message and starts the process all over again.

While this is the best solution we have at the moment, it's not the optimal one and will have to change as Azure Hosted Services comes out of the CTP stage and enters Beta or Release. A couple of items this doesn't address:

  • How responsive must a Worker Role be?
    If a Windows Service doesn't respond to a shutdown request in 30 seconds, it's considered "frozen" and Windows will instantly terminate the thread. It's unknown what the Worker Role will do or how long it will wait. It will probably be a requirement to handle a graceful shutdown that every time you call Notification you also check to see if you should stop processing.
  • Continuation of processing.
    If the Worker Role ends in the middle of a request, how do you gracefully continue? How Idempotent is your processing? In this particular example, if the request isn't in Pending status, the worker role just says it is in error and doesn't do anything.

Code Samples

The complete sample code can be downloaded here.

First, we have the basic plumbing that handles sending notifications back to whatever is calling the class:

enum WorkerRoleEventLogType
{
Critical,
Error,
Warning,
Information,
Verbose
}
/// <summary>/// Get messages from the Class as it processes/// </summary>/// <param name="message">Message data</param>public delegate void LogHandler(string messageType, string message);private LogHandler mvLogHandler;public void OnLogHandler(LogHandler msgString)
{
if (msgString != null)
{
mvLogHandler = msgString;
Console.WriteLine(msgString);
}
}
/// <summary>/// Notify the calling object of an event/// </summary>/// <param name="msg">Message of what has happened</param>void NotifyCaller(WorkerRoleEventLogType logType, string msg)
{
if (mvLogHandler != null)
mvLogHandler(logType.ToString(), msg);
}

Since we are using our Worker Class to handle all logging, we have enum that allows us to tell the Worker Class what type of logging we are doing along with the basic NotifyCaller method that will either have a handler defined for it or not. If the calling object has defined a handler for NotifyCaller, then we call it, passing in the parameters. If it hasn't then we just ignore the request made to NotifyCaller.

We have at least one property that we need to be able to set:

public bool stopProcessing { get; set; }

This property is used to to let us know that we need to stop processing because the Worker Role is shutting down. Just like with a Windows Service, our class needs to be able to wrap up whatever it's doing and stop processing if necessary. This value is set to True in the AcceptShutdown() and Stop() methods of the Worker Role.

Next we have the Initializer for the class. This takes the basic information needed for whatever job this  DLL needs to do. In this case, it will be getting queue information and processing bulk Azure Table Storage requests so the Initializer contains authentication information:

public bulkProcessing( string Account, string Key, string Tag)
{
dfltAccount = Account;
dfltKey =Key;
bulkTag = Tag;
}

 Note: Any values for the Initializer should be defined in the Service Configuration so that you can change them without the need to upload a new version of the software.

All of my classes that are designed to be called from Worker Roles or Windows Services all have a Process method which handles all of the work:

 public void Process()
{
AzureQueueStorage aqs = new AzureQueueStorage(dfltAccount, string.Format("http://{0}.queue.core.windows.net", dfltAccount), dfltKey, "SharedKey");
azureResults ar = aqs.Messages(cmdType.get, bulkTag, "", "visibilitytimeout=7200", "");string MessageID = string.Empty;string PopReceipt = string.Empty;string Message = string.Empty;string summaryKey = "_Summary";while (ar.Body != null)
{
// Do processing code hereif (!stopProcessing)
ar = aqs.Messages(cmdType.get, bulkTag, "", "visibilitytimeout=7200", "");elsebreak;
}
}

This code is getting a message off of the queue, if one exists, and processing it. When it's finished processing, it checks to see if the stopProcessing property is true. If it isn't, it looks for another message. If it is, it stops processing.

That's the simple method of writing a class to be instantiated by a Worker Role. If you have more complex processing requirements or your processing may take longer, you may need to use threads, a concept that I'll tackle sometime soon, when I've finished the basics.

That's all for today. In the next installment we will look at handling transactions in Azure Table Storage.

All Posts in Series:

Tags:

Your name:
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
Enter the code shown above in the box below
Add Comment  Cancel 
 
 
  
 
Privacy Statement | Terms Of Use Copyright 2001-2008 by ReluctantDBA.com