I have an Azure application that requires 3 uniquely unique tasks to run as lengthy processes. I could easily deploy 3 Worker Roles, but it would cost 3 times what I would have to spend, given how simple the tasks are. I would like to run each task in its own thread, since each task is different from the time it takes to complete, and how often it takes to complete.
Given this scenario or even the generic multi-threaded Azure scenario, what is the best way you know that each task runs independently?
A few considerations I would suggest are as follows:
- Keep the processor busy (not always possible with EventWaitHandles ..?).
- Uses the most advanced frame utilities (i.e. TPL or PLINQ).
- Graceful shutdown and reboot in the event of a fatal exception.
Thanks for the suggestions, links or sample code.
EDIT
Here's what I decided - given that the code is tied to an Azure cloud, the self-healing option seems the most appropriate. This approach aims at collecting a collection of threads and delegating their work to various โunits of workโ.
That's how he stuck together. First, a simple class to bring together diverse workers.
public class ThreadWorker { internal void RunInternal() { try { Run(); } catch (SystemException) { throw; } catch (Exception) { } } public virtual void Run() { } public virtual void OnStop() { } }
Next, the code is to keep the thread chain indefinitely. This includes a list of threads, a list of "workers" (one per thread) and an infinite loop that checks the status of each thread for a given interval.
Note that the exception that terminates the thread does not break other threads. If an unhandled exception occurs, the thread will be restarted the next time the event listener is called.
private readonly List<Thread> _threads = new List<Thread>(); private readonly List<ThreadWorker> _workers = new List<ThreadWorker>(); private EventWaitHandle EventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); public override void Run() { foreach (var worker in _workers) { _threads.Add(new Thread(worker.RunInternal)); } foreach (var thread in _threads) { thread.Start(); } while (!EventWaitHandle.WaitOne(500)) {
Simple enough - the main thread (in this case, the Run method of the Azure working role) blocks half a second between checks on the active list of threads. Completed threads are restarted, and the host thread is then blocked for 2 seconds before checking again that the workflows are working.
Adding workers is as simple as adding a list of classes that inherit from the ThreadWorker base class.
_workers.Add(new SomeWorker()); _workers.Add(new AnotherWorker());
And finally, specific workers:
public class SomeWorker: ThreadWorker { public override void Run() { while (true) {