protected override async Task ExecuteNodeTreeAsync(ExecutionContext context, ObjectExecutionNode rootNode) { var pendingNodes = new List <ExecutionNode> { rootNode }; var batchOperationHandler = CreateBatchOperationHandler(context); try { while (pendingNodes.Count > 0) { var currentTasks = new Task <ExecutionNode> [pendingNodes.Count]; // Start executing all pending nodes for (int i = 0; i < pendingNodes.Count; i++) { context.CancellationToken.ThrowIfCancellationRequested(); currentTasks[i] = ExecuteNodeAsync(context, pendingNodes[i]); } pendingNodes.Clear(); await OnBeforeExecutionStepAwaitedAsync(context); //batch data loader execution if (batchOperationHandler != null) { await batchOperationHandler.CompleteAsync(new Memory <Task>(currentTasks.Cast <Task>().ToArray()), context.CancellationToken); } else { await Task.WhenAll(currentTasks); } // Await tasks for this execution step foreach (var task in currentTasks) { var result = await task; if (result is IParentExecutionNode parentNode) { pendingNodes.AddRange(parentNode.GetChildNodes()); } } } } finally { batchOperationHandler?.Dispose(); } }
/// <inheritdoc/> protected override async Task ExecuteNodeTreeAsync(ExecutionContext context, ObjectExecutionNode rootNode) { if (context.RequestServices == null) { throw new ArgumentNullException($"{nameof(context)}.{nameof(ExecutionContext.RequestServices)}"); } Func <Task, ExecutionNode, Task <ExecutionNode> > taskFunc = async(task, node) => { await task; return(node); }; var nodes = new Stack <ExecutionNode>(); //synchronous nodes to be executed nodes.Push(rootNode); var asyncNodes = new Stack <ExecutionNode>(); //asynchronous nodes to be executed var waitingTasks = new List <Task <ExecutionNode> >(); //nodes currently executing var pendingNodes = new Queue <ExecutionNode>(); //IDelayLoadedResult nodes pending completion Task?waitingSyncTask = null; int maxTasks = context.MaxParallelExecutionCount ?? int.MaxValue; if (maxTasks < 1) { throw new InvalidOperationException("Invalid maximum number of tasks"); } void DICompleteNode(ExecutionNode node) { //if the result of the node is an IDelayLoadedResult, then add this // node to a list of nodes to be loaded once everything else possible // has been loaded if (node.Result is IDataLoaderResult) { pendingNodes.Enqueue(node); } else { // Push any child nodes on top of the stack if (node is IParentExecutionNode parentNode) { // Add in reverse order so fields are executed in the correct order (for synchronous tasks) foreach (var child in parentNode.GetChildNodes().Reverse()) { //add node to async list or sync list, as appropriate if (child.FieldDefinition is DIFieldType fieldType && fieldType.Concurrent) { asyncNodes.Push(child); } else { nodes.Push(child); } } } }