internal ExecutionContext(ExecutionContextData contextData, IExecutionContext parent, IModule module, ImmutableArray <IDocument> inputs)
        {
            _contextData = contextData ?? throw new ArgumentNullException(nameof(contextData));
            _logger      = CreateLogger(parent, module, contextData.PipelinePhase, contextData.Services.GetRequiredService <ILoggerFactory>());

            Parent = parent;
            Module = module ?? throw new ArgumentNullException(nameof(module));
            Inputs = inputs;
        }
Exemple #2
0
        internal ExecutionContext(ExecutionContextData contextData, IExecutionContext parent, IModule module, ImmutableArray <IDocument> inputs)
        {
            _contextData = contextData ?? throw new ArgumentNullException(nameof(contextData));
            _logger      = contextData.Services.GetRequiredService <ILogger <ExecutionContext> >();
            _logPrefix   = GetLogPrefix(parent, module, contextData.PipelinePhase);

            Parent = parent;
            Module = module ?? throw new ArgumentNullException(nameof(module));
            Inputs = inputs;

            IExecutionContext.Current = this;
        }
Exemple #3
0
        // This is the main execute method called by the engine
        public async Task ExecuteAsync(
            Engine engine,
            Guid executionId,
            CancellationTokenSource cancellationTokenSource)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(PipelinePhase));
            }

            if (_modules.Count == 0)
            {
                _logger.LogDebug($"Pipeline {PipelineName}/{Phase} contains no modules, skipping");
                Outputs = GetInputs();
                return;
            }

            System.Diagnostics.Stopwatch pipelineStopwatch = System.Diagnostics.Stopwatch.StartNew();
            _logger.LogDebug($"Executing pipeline {PipelineName}/{Phase} with {_modules.Count} module(s)");
            try
            {
                // Execute all modules in the pipeline with a new DI scope per phase
                IServiceScopeFactory serviceScopeFactory = engine.Services.GetRequiredService <IServiceScopeFactory>();
                using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
                {
                    ExecutionContextData contextData = new ExecutionContextData(engine, executionId, this, serviceScope.ServiceProvider, cancellationTokenSource.Token);
                    Outputs = await Engine.ExecuteModulesAsync(contextData, null, _modules, GetInputs(), _logger);

                    pipelineStopwatch.Stop();
                    _logger.LogInformation($"Executed pipeline {PipelineName}/{Phase} in {pipelineStopwatch.ElapsedMilliseconds} ms resulting in {Outputs.Length} output document(s)");
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    _logger.LogCritical($"Exception while executing pipeline {PipelineName}/{Phase}: {ex}");
                    cancellationTokenSource.Cancel();
                }
                Outputs = ImmutableArray <IDocument> .Empty;
                throw;
            }

            // Store the result documents, but only if this is the Process phase of a non-isolated pipeline
            if (!Pipeline.Isolated && Phase == Phase.Process)
            {
                engine.Documents.AddOrUpdate(
                    PipelineName,
                    Outputs,
                    (_, __) => Outputs);
            }
        }
Exemple #4
0
        // This executes the specified modules with the specified input documents
        internal static async Task <ImmutableArray <IDocument> > ExecuteModulesAsync(ExecutionContextData contextData, IExecutionContext parent, IEnumerable <IModule> modules, ImmutableArray <IDocument> inputs, ILogger logger)
        {
            ImmutableArray <IDocument> outputs = ImmutableArray <IDocument> .Empty;

            if (modules != null)
            {
                foreach (IModule module in modules.Where(x => x != null))
                {
                    string moduleName = module.GetType().Name;

                    try
                    {
                        // Check for cancellation
                        contextData.CancellationToken.ThrowIfCancellationRequested();

                        // Execute the module
                        System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
                        logger.LogDebug("Executing module {0} with {1} input document(s)", moduleName, inputs.Length);
                        ExecutionContext        moduleContext = new ExecutionContext(contextData, parent, module, inputs);
                        IEnumerable <IDocument> moduleResult  = await(module.ExecuteAsync(moduleContext) ?? Task.FromResult <IEnumerable <IDocument> >(null)); // Handle a null Task return
                        outputs = moduleResult.ToImmutableDocumentArray();

                        // Log results
                        stopwatch.Stop();
                        logger.LogDebug(
                            "Executed module {0} in {1} ms resulting in {2} output document(s)",
                            moduleName,
                            stopwatch.ElapsedMilliseconds,
                            outputs.Length);
                        inputs = outputs;
                    }
                    catch (Exception ex)
                    {
                        if (!(ex is OperationCanceledException))
                        {
                            logger.LogError($"Error while executing module {moduleName}: {ex.Message}");
                        }
                        outputs = ImmutableArray <IDocument> .Empty;
                        throw;
                    }
                }
            }
            return(outputs);
        }
        // This is the main execute method called by the engine
        public async Task ExecuteAsync(Engine engine, ConcurrentDictionary <string, PhaseResult[]> phaseResults)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(PipelinePhase));
            }

            // Raise the before event
            await engine.Events.RaiseAsync(new BeforePipelinePhaseExecution(engine.ExecutionId, PipelineName, Phase));

            // Skip the phase if there are no modules
            if (_modules.Count == 0)
            {
                _logger.LogDebug($"{PipelineName}/{Phase} » Pipeline contains no modules, skipping");
                Outputs = GetInputs();
                return;
            }

            // Execute the phase
            ImmutableArray <IDocument> inputs    = GetInputs();
            DateTimeOffset             startTime = DateTimeOffset.Now;

            System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
            _logger.LogInformation($"-> {PipelineName}/{Phase} » Starting {PipelineName} {Phase} phase execution... ({inputs.Length} input document(s), {_modules.Count} module(s))");
            try
            {
                // Execute all modules in the pipeline with a new DI scope per phase
                IServiceScopeFactory serviceScopeFactory = engine.Services.GetRequiredService <IServiceScopeFactory>();
                using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
                {
                    ExecutionContextData contextData = new ExecutionContextData(
                        this,
                        engine,
                        phaseResults,
                        serviceScope.ServiceProvider);
                    Outputs = await Engine.ExecuteModulesAsync(contextData, null, _modules, inputs, _logger);

                    stopwatch.Stop();
                    _logger.LogInformation($"   {PipelineName}/{Phase} » Finished {PipelineName} {Phase} phase execution ({Outputs.Length} output document(s), {stopwatch.ElapsedMilliseconds} ms)");
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    _logger.LogCritical($"Exception while executing pipeline {PipelineName}/{Phase}: {ex}");
                }
                Outputs = ImmutableArray <IDocument> .Empty;
                throw;
            }
            finally
            {
                stopwatch.Stop();
            }

            // Raise the after event
            await engine.Events.RaiseAsync(new AfterPipelinePhaseExecution(engine.ExecutionId, PipelineName, Phase, Outputs, stopwatch.ElapsedMilliseconds));

            // Record the results
            PhaseResult phaseResult = new PhaseResult(PipelineName, Phase, Outputs, startTime, stopwatch.ElapsedMilliseconds);

            phaseResults.AddOrUpdate(
                phaseResult.PipelineName,
                _ =>
            {
                PhaseResult[] results           = new PhaseResult[4];
                results[(int)phaseResult.Phase] = phaseResult;
                return(results);
            },
                (_, results) =>
            {
                if (results[(int)phaseResult.Phase] != null)
                {
                    // Sanity check, we should never hit this
                    throw new InvalidOperationException($"Results for phase {phaseResult.Phase} have already been added");
                }
                results[(int)phaseResult.Phase] = phaseResult;
                return(results);
            });
        }