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();
            }
        }
Ejemplo n.º 2
0
        /// <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);
                            }
                        }
                    }
                }