Ejemplo n.º 1
0
 public ExecutionContextData(Engine engine, Guid executionId, PipelinePhase pipelinePhase, IServiceProvider services, CancellationToken cancellationToken)
 {
     Engine            = engine ?? throw new ArgumentNullException(nameof(engine));
     ExecutionId       = executionId;
     PipelinePhase     = pipelinePhase ?? throw new ArgumentNullException(nameof(pipelinePhase));
     Services          = services ?? throw new ArgumentNullException(nameof(services));
     Outputs           = new PipelineOutputs(engine.Documents, pipelinePhase, engine.Pipelines);
     CancellationToken = cancellationToken;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Executes the specified pipelines and pipelines with <see cref="ExecutionPolicy.Always"/> policies.
        /// </summary>
        /// <param name="pipelines">
        /// The pipelines to execute or <c>null</c>/empty to only execute pipelines with the <see cref="ExecutionPolicy.Always"/> policy.
        /// </param>
        /// <param name="normalPipelines">
        /// <c>true</c> to run pipelines with the <see cref="ExecutionPolicy.Normal"/> policy in addition
        /// to the pipelines specified or <c>false</c> to only run the specified pipelines.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token that can be used to cancel the execution.
        /// </param>
        /// <returns>The output documents from each executed pipeline.</returns>
        public async Task <IPipelineOutputs> ExecuteAsync(string[] pipelines, bool normalPipelines, CancellationToken cancellationToken = default)
        {
            // Setup
            await default(SynchronizationContextRemover);
            CheckDisposed();

            // Make sure only one execution is running
            if (ExecutionId != Guid.Empty)
            {
                throw new ExecutionException($"Execution with ID {ExecutionId} is already executing, only one execution can be run at once");
            }
            ExecutionId       = Guid.NewGuid();
            CancellationToken = cancellationToken;
            try
            {
                // Create the phase results for this execution
                ConcurrentDictionary <string, PhaseResult[]> phaseResults =
                    new ConcurrentDictionary <string, PhaseResult[]>(StringComparer.OrdinalIgnoreCase);
                Outputs = new PipelineOutputs(phaseResults);

                // Create the pipeline phases (this also validates the pipeline graph)
                if (_phases == null)
                {
                    _phases = GetPipelinePhases(_pipelines, _logger);
                }

                // Verify pipelines
                HashSet <string> executingPipelines = GetExecutingPipelines(pipelines, normalPipelines);
                if (executingPipelines.Count == 0)
                {
                    _logger.LogWarning("No pipelines are configured or specified for execution.");
                    return(Outputs);
                }

                // Log
                _logger.LogInformation($"Executing {executingPipelines.Count} pipelines ({string.Join(", ", executingPipelines.OrderBy(x => x))})");
                _logger.LogDebug($"Execution ID {ExecutionId}");
                System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();

                // Raise before event
                await Events.RaiseAsync(new BeforeEngineExecution(this, ExecutionId));

                // Do a check for the same input/output path
                if (FileSystem.InputPaths.Any(x => x.Equals(FileSystem.OutputPath)))
                {
                    _logger.LogWarning("The output path is also one of the input paths which can cause unexpected behavior and is usually not advised");
                }

                // Clean paths
                CleanTempPath();
                if (Settings.GetBool(Keys.CleanOutputPath))
                {
                    CleanOutputPath();
                }

                // Get and run all phase tasks
                Task[] phaseTasks = null;
                try
                {
                    // Get and execute all phases
                    phaseTasks = GetPhaseTasks(executingPipelines, phaseResults);
                    await Task.WhenAll(phaseTasks);
                }
                finally
                {
                    stopwatch.Stop();
                }

                // Raise after event
                await Events.RaiseAsync(new AfterEngineExecution(this, ExecutionId, Outputs, stopwatch.ElapsedMilliseconds));

                // Log execution summary table
                if (phaseResults.Count > 0)
                {
                    _logger.LogInformation(GetExecutionSummary(phaseResults));
                }

                // Clean up
                _logger.LogInformation($"Finished execution in {stopwatch.ElapsedMilliseconds} ms");
                return(Outputs);
            }
            finally
            {
                ExecutionId       = Guid.Empty;
                CancellationToken = default;
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Executes the specified pipelines and pipelines with <see cref="ExecutionPolicy.Always"/> policies.
        /// </summary>
        /// <param name="pipelines">
        /// The pipelines to execute or <c>null</c>/empty to only execute pipelines with the <see cref="ExecutionPolicy.Always"/> policy.
        /// </param>
        /// <param name="defaultPipelines">
        /// <c>true</c> to run the default pipelines in addition to the pipelines specified
        /// or <c>false</c> to only run the specified pipelines.
        /// </param>
        /// <param name="cancellationTokenSource">
        /// A cancellation token source that can be used to cancel the execution.
        /// </param>
        /// <returns>The output documents from each executed pipeline.</returns>
        public async Task <IPipelineOutputs> ExecuteAsync(string[] pipelines, bool defaultPipelines, CancellationTokenSource cancellationTokenSource)
        {
            // Setup
            await default(SynchronizationContextRemover);
            CheckDisposed();
            Guid executionId = Guid.NewGuid();
            ConcurrentDictionary <string, PhaseResult[]> phaseResults =
                new ConcurrentDictionary <string, PhaseResult[]>(StringComparer.OrdinalIgnoreCase);
            PipelineOutputs outputs = new PipelineOutputs(phaseResults);

            // Create the pipeline phases (this also validates the pipeline graph)
            // Also add the service-based pipelines as late as possible so other services have been configured
            if (_phases == null)
            {
                AddServicePipelines();
                _phases = GetPipelinePhases(_pipelines, _logger);
            }

            // Verify pipelines
            HashSet <string> executingPipelines = GetExecutingPipelines(pipelines, defaultPipelines);

            if (executingPipelines.Count == 0)
            {
                _logger.LogWarning("No pipelines are configured or specified for execution.");
                return(outputs);
            }

            // Log
            _logger.LogInformation($"Executing {executingPipelines.Count} pipelines ({string.Join(", ", executingPipelines.OrderBy(x => x))})");
            _logger.LogDebug($"Execution ID {executionId}");
            System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();

            // Raise before event
            await Events.RaiseAsync(new BeforeEngineExecution(this, executionId));

            // Do a check for the same input/output path
            if (FileSystem.InputPaths.Any(x => x.Equals(FileSystem.OutputPath)))
            {
                _logger.LogWarning("The output path is also one of the input paths which can cause unexpected behavior and is usually not advised");
            }

            // Clean paths
            CleanTempPath();
            if (Settings.GetBool(Keys.CleanOutputPath))
            {
                CleanOutputPath();
            }

            // Get phase tasks
            Task[] phaseTasks = null;
            try
            {
                // Get and execute all phases
                phaseTasks = GetPhaseTasks(executionId, executingPipelines, phaseResults, cancellationTokenSource);
                await Task.WhenAll(phaseTasks);
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    _logger.LogCritical("Error during execution");
                }
                throw;
            }
            finally
            {
                stopwatch.Stop();
            }

            // Raise after event
            await Events.RaiseAsync(new AfterEngineExecution(this, executionId, outputs, stopwatch.ElapsedMilliseconds));

            // Log execution summary table
            _logger.LogInformation(
                "Execution summary: (number of output documents per pipeline and phase)"
                + Environment.NewLine
                + Environment.NewLine
                + phaseResults
                .OrderBy(x => x.Key)
                .ToStringTable(
                    new[]
            {
                "Pipeline",
                nameof(Phase.Input),
                nameof(Phase.Process),
                nameof(Phase.Transform),
                nameof(Phase.Output),
                "Total Time"
            },
                    x => x.Key,
                    x => GetPhaseResultTableString(x.Value[(int)Phase.Input]),
                    x => GetPhaseResultTableString(x.Value[(int)Phase.Process]),
                    x => GetPhaseResultTableString(x.Value[(int)Phase.Transform]),
                    x => GetPhaseResultTableString(x.Value[(int)Phase.Output]),
                    x =>
                    ((x.Value[(int)Phase.Input]?.ElapsedMilliseconds ?? 0)
                     + (x.Value[(int)Phase.Process]?.ElapsedMilliseconds ?? 0)
                     + (x.Value[(int)Phase.Transform]?.ElapsedMilliseconds ?? 0)
                     + (x.Value[(int)Phase.Output]?.ElapsedMilliseconds ?? 0)).ToString()
                    + " ms"));