August 12th, 2011
Worker roles are a great resource we can use to execute background tasks like integration, migration, scheduling tasks, etc, but also are very useful to run asynchronous tasks triggered by the user. All this kind of processes usually are composed by a set of steps, and we usually hardcode the flow in which those steps are executed. In very trivial cases this is not a problem, but in real and complex scenarios this “flow” magament code increases the lines of code, which complicates the maintainability of our code, as well as the response to change factor.
Yes, as you can imagine, using Workflow is a very nice and powerful way of avoid all that extra code you need to coordinate the process, just keeping focus on writing the code you need to carry out the functionality you need.
In this post I’ll show you how to create a very simple Workflow-Driven WorkerRole, that reads a message from a queue and sends an email.
If you want to download the code click here.
Creating Custom Activities
To accomplish our objective we will need to create a few Custom activities, due to the functionality we need is not included in WF 4.0 out of the box (you can see a list of the provided activities here). I will quickly show how to create one of them without much detail, due to this is not the subject for this post. We will create three different custom activities:
ReadMessageFromQueue: This will be the activity we going to use to read the message from the queue.
DeleteMessageFromQueue: This activity will delete the message after it has been processed.
SendEmail: As you can guess, this activity will be the responsible for sending the email.
First of all we need to create a new WorkerRole project called “SubscriptionEmailSender” (I’m not going to detail this, I’m guessing that this is not your first worker role). Once we have that, we will add an “Activities” folder, where we going to add our custom activities.
To create a custom activity, we just need to right click the “Activities” folder and Add New Item and use the Code Activity template.
This template will add a class to our project, that extends type System.Activities.CodeActivity, just like a “Command Pattern” this will force us to provide an implementation for a method called “Execute” that will be called when the activity is executed.
We will create the ReadMessageFromQueue activity, basically we need to read and retrieve a message from a queue, but note that the Execute method is a void method, to change that we need to change this class to extend the class System.Activities.CodeActivity<TResult>, also we need two input parameters, the name of the queue we want to read and the Azure storage account we going to use to do that.
Notice that to read the parameters values you need to use the context.GetValue(parameter) method. I’ve also added the Designer attribute, this allows me to use a nice XAML designer for the activity that you’ll see in the solution. Build and it’s done.
Creating the Workflow
Once we have all the activities we need, we can start to create the workflow. To do that, right click the WorkerRole project and add new item, using the “Activity” template.
In WF 4.0 there is not a Workflow concept, everything is an activity, so we call “Workflow” to an activity composed of other activities. In our case, our workflow need to do the next:
Read message from the “newsubscriptions” queue.
If no message is present, wait 10 seconds and go to step 1.
If a message is present, send a welcome message to the email address. (the email address will be the message text)
Deletes the message.
Go to step 1.
Let’s start, In the workflow designer, click in the “arguments” tab in the down-left corner, and add the next argument:
This means that our workflow will receive as argument the CloudStorageAccount that we are going to use to work with the queue. Always that we talk about “if” in a workflow we are talking about a flowchart, and that’s the first activity we need to drop in our workflow designer.
Also we need to create a variable at Flowchart level named “Message” where the message will store the message.
Drop the ReadMessageFromQueue activity from the toolbox to the flowchart as initial activity, and configure these values in the property window and tie the start icon to the ReadMessageFromQueue activity.
Account: Account (this makes reference to the Account argument we set in the first step.
Result: Message (this means that the result will be put in the Message variable we set in the previous step)
Now drop a FlowchartDecision activity, tie the ReadMessageFromQueue activity to this one and set these values in the property window:
TrueLabel: “No Message”
To continue, drop a Delay activity and tie the “No Message” endpoint of the FlowchartDecision activity to it and tie it to the ReadMessageFromQueue activity. Also set in property window this value:
- Duration: 00:00:10
Now drop the SendEmail activity, tie the “Message!” endpoint of the FlowchartDecision to it, and configure this values in the properties window:
- Message: “Welcome to WF & Azure happiness”
- Subject: “Welcome “ + Message.AsString
- To: Message.AsString
To finish, drop the DeleteMessageFromQueue activity, tie the SendEmail activity to it, also tie it to the ReadMessageFromQueue and set this values in the properties window:
- QueueName: “newsubscriptions”
- Message: Message
- Account: Account
You should have something like this:
Writing the WorkerRole
Now that we have the Workflow completed, we just need to execute it from the WorkeRole, and this is all the code we need to do that.
As you can see, the only thing we need to do is call to WorkflowInvoker providing the instance of the workflow that we want to execute, and the arguments that it is expecting. As our workflow has no end, we don’t need the typical while(true) instruction to keep the process alive.
That’s all, It wasn’t hard at all, right?. To close this post I leave some points to think about:
- We just write code to fit our functional requirements, we completely avoid the process management code.
- All tasks we’ve created are very reusable.
- In a complex process, to have a graphical map of it, is really very useful.
- If something change in the process you just need to change the workflow without touching any line of code.
- The workflow XAML file could be stored in Azure’s Blob storage and that would allow you to avoid re-deploy to make a change in the process. In my next post I’ll show how to do that.
Hope be useful!