DependentTaskRunner – How to Run Tasks with Dependencies and Stay Sane

0
67

Introduction

When you have multiple tasks to perform, it can really help if you can do some of them in parallel. However, when they are dependent on each other, it sometimes becomes a real pain to manage which tasks can be performed in parallel, and sometimes programmers prefer to give up and perform the tasks sequentially to avoid this pain. I didn’t find any library that handles this problem, so I decided to write my own one ( DependentTaskRunner ) to make the life a little bit easier. In this tip I will explain how to use this library on a very simple example. The solution is pretty much scalable for more complex cases as well.

Using the code

Open a new Visual Studio console application and add the DependentTaskRunner nuget package to it:

Install It:

In Program.cs file, add this using:

using DependentTaskRunner;

Create a new class called MyTask:

public class MyTask
{
    public MyTask[] Dependencies { get; set; }
    public Func<bool> Perform { get; set; }
}

Write the taskRunner initialization code in the Main function:

var taskRunner = new TaskRunner<MyTask>(t => t.Dependencies, t => Task.Run(() => t.Perform()));

Now we need to write the code that performs the tasks.

Suppose that you want to perform 3 tasks : A,B,C.

C can be performed only after A and B are finished:

Each task is represented as a function that returns a boolean value that indicates whether the task finished successfully or failed:

private static bool RunA()
{
    Console.WriteLine(DateTime.Now + " A Started");
    Thread.Sleep(2000); 
    Console.WriteLine(DateTime.Now + " A Finished");
    return true;
}

private static bool RunB()
{
    Console.WriteLine(DateTime.Now + " B Started");
    Thread.Sleep(3000); 
    Console.WriteLine(DateTime.Now + " B Finished");
    return true;
}

private static bool RunC()
{
    Console.WriteLine(DateTime.Now + " C Started");
    Thread.Sleep(4000); 
    Console.WriteLine(DateTime.Now + " C Finished");
    return true;
}

Now we need to create the task objects in the Main function:

var taskA = new MyTask { Perform = RunA };
var taskB = new MyTask { Perform = RunB };
var taskC = new MyTask { Dependencies = new[] { taskA, taskB }, Perform = RunC };

And make the tasks start running:

taskRunner.PerformTasks(new[] { taskA, taskB, taskC });

And this is it.

Now we can run the code:

We can see that A and B were performed in parallel and C is performed only after A and B are both finished.

The whole code sholud look like this now:

class Program
{
 static void Main(string[] args)
 {
 var taskRunner = new TaskRunner<MyTask>(t => t.Dependencies, t => Task.Run(() => t.Perform()));

 var taskA = new MyTask { Perform = RunA };
 var taskB = new MyTask { Perform = RunB };
 var taskC = new MyTask { Dependencies = new[] { taskA, taskB }, Perform = RunC };

 taskRunner.PerformTasks(new[] { taskA, taskB, taskC });

 Console.ReadLine();
 }

 private static bool RunA()
 {
 Console.WriteLine(DateTime.Now + " A Started");
 Thread.Sleep(2000); 
 Console.WriteLine(DateTime.Now + " A Finished");
 return true;
 }

 private static bool RunB()
 {
 Console.WriteLine(DateTime.Now + " B Started");
 Thread.Sleep(3000); 
 Console.WriteLine(DateTime.Now + " B Finished");
 return true;
 }

 private static bool RunC()
 {
 Console.WriteLine(DateTime.Now + " C Started");
 Thread.Sleep(4000); 
 Console.WriteLine(DateTime.Now + " C Finished");
 return true;
 }

 public class MyTask
 {
 public MyTask[] Dependencies { get; set; }
 public Func<bool> Perform { get; set; }
 }
}

Pay attention that if a function of a task returns false, the tasks that depends on it will never be performed, for example if we will change the RunA function:

private static bool RunA()
{
 Console.WriteLine(DateTime.Now + " A Started");
 Thread.Sleep(2000); 
 Console.WriteLine(DateTime.Now + " A Finished");
 return false;
}

This is the result we will get:

The C Task is never performed because the A task failed.

I showed only one very basic way to use the library, if you would like to use Async/Await you can find an example here. There are more examples to using the libary here.

What’s Next?

My code is actually open source and can be found here.

If you want some explanations about the code, I will be glad to write another article with explanations.

Feel free to write any suggestions or issues you have found.

Useful Links

DependentTaskRunner Nuget package.

DependentTaskRunner repository on GitHub.

LEAVE A REPLY