I have 3 tasks in my application that are responsible for getting data from databases.
Till now I had all tasks executed one after one. If first finished and had Result then this was my data, if now I started second task and I checked again.
Recently I found information that I can start multiple tasks and continue when one of them finish using Task.Factory.ContinueWhenAny
. This works fine if all my task don't throw any Exceptions, but if any Task fails I can't get results I want.
For example:
var t1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 1;
});
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
throw new Exception("My error");
return 2;
});
var t3 = Task.Factory.StartNew(() =>
{
Thread.Sleep(4000);
return 3;
});
Task.Factory.ContinueWhenAny(new[] {t1, t2,t3}, (t) =>
{
Console.WriteLine(t.Result);
});
This code starts 3 tasks and waits till one of them finish.
Because t2
throws exception after 2 seconds it is the one that is available in ContinueWhenAny
.
From code above I would like to get 3 in t.Result
.
Is there an option to continue only when task finished successfully? Something like Task.Factory.ContinueWhenAnyButSkipFailedTasks
EDIT 1 This is my solution for now based on @Nitram answer:
var t1 = Task.Factory.StartNew(() =>
{
var rnd = new Random();
Thread.Sleep(rnd.Next(5,15)*1000);
throw new Exception("My error");
return 1;
});
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
throw new Exception("My error");
return 2;
});
var t3 = Task.Factory.StartNew(() =>
{
throw new Exception("My error");
return 3;
});
var tasks = new List<Task<int>> { t1, t2, t3 };
Action<Task<int>> handler = null;
handler = t =>
{
if (t.IsFaulted)
{
tasks.Remove(t);
if (tasks.Count == 0)
{
throw new Exception("No data at all!");
}
Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
}
else
{
Console.WriteLine(t.Result);
}
};
Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
What I need now is how to throw exception when all tasks throw exception?
Maybe this can be changed into single method that would return task - something like child tasks?