/// <summary> /// Used to kick off execution of a node with a default execution context for all subjects using Async WhenAll semantics internally . /// </summary> /// <param name="subjects">Subject to be moved through the node.</param> /// <param name="options">Execution options to apply to running this enumerable of subjects.</param> /// <returns>An aggregated NodeResult.</returns> public async Task <NodeResult> ExecuteManyAsync(IEnumerable <T> subjects, ExecutionOptions options = null) { Guard.AgainstNullArgument("subjects", subjects); var nodeTimer = new NodeTimer(); try { nodeTimer.LogStart(LogWriter, this, "ExecuteManyAsync"); _processManyMode = true; Result = new NodeResult(default(T), Id, FlowId); var subjectList = subjects.ToList(); if (subjectList.Count == 0) { return(Result); } if (options == null) { options = new ExecutionOptions(); } LogWriter.Debug("Running all subjects asynchronously."); Task aggregateTask = null; try { var resultsQueue = new ConcurrentQueue <NodeResult>(); aggregateTask = subjectList.ForEachAsync(options.DegreeOfParallelism, async x => resultsQueue.Enqueue(await ExecuteAsync(new ExecutionContext <T>(x, options)))); await aggregateTask; Result.AddChildResults(resultsQueue); } catch { if (options.ThrowOnError) { if (aggregateTask != null && aggregateTask.Exception != null) { throw aggregateTask.Exception; } throw; } } ProcessExecuteManyResults(options); return(Result); } finally { _processManyMode = false; nodeTimer.LogStop(LogWriter, this, "ExecuteAsync"); } }
/// <summary> /// Used to kick off execution of a node with a default execution context for all subjects in a serial manner. /// </summary> /// <param name="subjects">Subject to be moved through the node.</param> /// <param name="options">Execution options to apply to running this enumerable of subjects.</param> /// <returns>An aggregated NodeResult.</returns> public async Task <NodeResult> ExecuteManySeriallyAsync(IEnumerable <T> subjects, ExecutionOptions options = null) { Guard.AgainstNullArgument("subjects", subjects); var nodeTimer = new NodeTimer(); try { nodeTimer.LogStart(LogWriter, this, "ExecuteManySeriallyAsync"); _processManyMode = true; var subjectList = subjects.ToList(); Result = new NodeResult(default(T), Id, FlowId); if (subjectList.Count == 0) { return(Result); } if (options == null) { options = new ExecutionOptions(); } foreach (var subject in subjectList) { try { LogWriter.Debug("Running all subjects asynchronously in a serial manner."); NodeResult result = await ExecuteAsync(new ExecutionContext <T>(subject, options)).ConfigureAwait(false); Result.AddChildResult(result); } catch (Exception) { if (options.ThrowOnError) { throw; } if (!options.ContinueOnFailure) { break; } } } ProcessExecuteManyResults(options); return(Result); } finally { _processManyMode = false; nodeTimer.LogStop(LogWriter, this, "ExecuteAsync"); } }
/// <summary> /// Used to kick off execution of a node with a specified execution context. /// </summary> /// <param name="sourceContext">ExecutionContext that includes a subject to be moved through the node.</param> /// <returns>A NodeResult</returns> public async Task <NodeResult> ExecuteAsync(IExecutionContext <T> sourceContext) { Guard.AgainstNullArgument("context", sourceContext); Guard.AgainstNullArgumentProperty("context", "Subject", sourceContext.Subject); var nodeTimer = new NodeTimer(); try { nodeTimer.LogStart(LogWriter, this, "ExecuteAsync"); if (Status != NodeRunStatus.NotRun) { LogWriter.Debug("Status does not equal 'NotRun', resetting the node before execution"); Reset(); } var subject = sourceContext.Subject; var result = new NodeResult(subject, Id, FlowId); if (!_processManyMode) { Result = result; } IExecutionContext <T> context = PrepareExecutionContext(sourceContext, result); OnBeforeExecute(context); if (!context.CancelProcessing) { var effectiveOptions = GetEffectiveOptions(context.GlobalOptions); if (!await ShouldExecuteInternalAsync(context).ConfigureAwait(false)) { LogWriter.Info("ShouldExecute returned false, skipping execution"); return(result); } Status = NodeRunStatus.Running; LogWriter.Debug("Executing the node"); try { result.Status = await PerformExecuteAsync(context).ConfigureAwait(false); //Reset the subject in case it was changed. result.Subject = context.Subject; Status = NodeRunStatus.Completed; LogWriter.Info("Node completed execution, status is {0}", result.Status); } catch (Exception ex) { LogWriter.Error("Node erred during execution, status is Failed", ex); Status = NodeRunStatus.Faulted; result.Subject = context.Subject; result.Status = NodeResultStatus.Failed; result.Exception = ex; if (effectiveOptions.ThrowOnError) { throw; } } OnAfterExecute(context); } sourceContext.CancelProcessing = context.CancelProcessing; return(result); } finally { nodeTimer.LogStop(LogWriter, this, "ExecuteAsync"); } }