I have a situation where I have some DB queries that need to be fired off. Some of these require the results of the previous query to run, which forms a hierarchy of sorts.
I want it so that when 1 query finishes, I can process that data without waiting for the children queries to finish. It's also possible that a hierarchy will stop early if the query returned no data.
I don't need/want the end result as a hierarchy, so having the results flattened is the goal (Similar to how I have a List<IEnumerable> in the example).
I have changed some things for simplicity, but general gist of what I have currently is:
private static async Task ProcessQueries(Foo initialFoo)
{
var allEntities = new List<IEnumerable<object>>();
var runningProcesses = new List<Task<Bar>>();
var queriesToProcess = new Queue<Foo>();
queriesToProcess.Enqueue(initialFoo);
while (runningProcesses.Count > 0 || queriesToProcess.Count > 0)
{
while (queriesToProcess.Count > 0)
{
var fooToProcess = queriesToProcess.Dequeue();
runningProcesses.Add(ProcessFoo(fooToProcess));
}
// As soon as any of the 'ProcessFoo' have finished, it means the query for the entities has finished
// And it might have more Foo's for us to process.
// I want to call ProcessFoo as soon as possible as that actually starts the query.
var finishedProcess = await Task.WhenAny(runningProcesses).ConfigureAwait(false);
runningProcesses.Remove(finishedProcess);
var finishedFoo = finishedProcess.Result;
foreach (var childFoo in finishedFoo.ChildFoos)
{
queriesToProcess.Enqueue(childFoo);
}
// I can now pass the entities to something else to process it without stopping the loop
// In this example I just add it to the list
allEntities.Add(finishedFoo.Entities);
}
}
Foo just contains all the information needed to start off the query.
Bar contains the entities, plus a list of additional Foo's to run.
I read about potential issues with Task.WhenAny if it grows too large. I don't think his solution applies to me here because my list of tasks is not a fixed size.
I'm wondering if there a more efficient way to accomplish this? Or if there are any existing designs for this kind of work?