Question for you: if your application has 2 “background” task to perform, do you implement this as 2 distinct workers? or as 1 worker with 2 responsibilities?
Option 1 is straight forward. Option 2 requires more work, but … does it make sense? It turns out that it does make sense. In some cases it makes a lot of sense.
In considering these options you have to remember that you are strongly encouraged to use your compute nodes. It doesn’t matter if your workers are sitting idling waiting for work to be done or busily crunching data and steaming by the computational complexity: you always pay the same!
Note: in fact, you pay by “provisioned” compute nodes. Even if the nodes are stopped, you still pay.
So you are strongly encouraged to increase the density of our computing nodes with as much work as possible. If Task 1 and Task 2 are “lightweight” processes that run every once in a while, then you rewarded by the second model, because you have a better chance of idling less. If, Task 1 is really intensive and you have a lot to do, then it is better to dedicate a full machine to it.
Notice that Option 1 is a special case of Option 2. You can model Option 1 by just having 1 thread in the worker dedicated to it.
The main disadvantage of Option 2 is that there are currently no abstractions in the Windows Azure SDK to deal with these “Tasks”. All the scheduling, error handling, etc. is up to you. Windows Azure visibility is at the macro level of the entire worker. For example, if one of your tasks (which is running in its own Thread) dies, Windows Azure won’t know about that and can’t do much. If the entire Worker dies, then Windows Azure will do its best to recover the defunct instance and will try to spawn a new one.
All the engineering to manage these “Tasks” is not complicated, but definitely qualifies as “plumbing” code: the code that we love writing, but that most people are not paid to :-).
The good news is that numerous samples and lightweight frameworks exist today that demonstrate this approach. A great sample is BidNow. The Worker Run() method in BidNow looks like this:
All handlers derive from a base class that implements the basic processing loop:
Our friend David Aiken, is doing a series of posts on BidNow that I’d suggest looking in more detail. There’re roughly a couple other samples that implement a similar design pattern (like the Windows Azure Facebook Toolkit) and now ours :-).
In a-Expense, there are 2 background processes: one to compress pictures and generate thumbnails and another one to create flat files with expenses records to reimburse. The latter is meant to be consumed by another system in Adatum. Because these 2 are rather lightweight (especially the second one that runs once a day or so) it just doesn’t make sense to have specialized workers.
The design we are following is very similar to what I described above. We’ll hopefully will have a new code drop soon. Stay tuned!