Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove parallel call Fixes #7946 #8635

Open
wants to merge 3 commits into
base: release/9.0.2xx
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 67 additions & 130 deletions src/Microsoft.TemplateEngine.Edge/TemplateConstraintManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,16 @@ public class TemplateConstraintManager : IDisposable
{
private readonly ILogger<TemplateConstraintManager> _logger;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly Dictionary<string, Task<ITemplateConstraint>> _templateConstrains = new Dictionary<string, Task<ITemplateConstraint>>();
private readonly Dictionary<string, ITemplateConstraint> _templateConstraints = new();
private readonly Dictionary<(string Type, string? Args), TemplateConstraintResult> _evaluatedConstraints = new();

public TemplateConstraintManager(IEngineEnvironmentSettings engineEnvironmentSettings)
{
_logger = engineEnvironmentSettings.Host.LoggerFactory.CreateLogger<TemplateConstraintManager>();

var constraintFactories = engineEnvironmentSettings.Components.OfType<ITemplateConstraintFactory>();
_logger.LogDebug($"Found {constraintFactories.Count()} constraints factories, initializing.");
foreach (var constraintFactory in constraintFactories)
{
_templateConstrains[constraintFactory.Type] = Task.Run(() => constraintFactory.CreateTemplateConstraintAsync(engineEnvironmentSettings, _cancellationTokenSource.Token));
}

InitializeTemplateConstraints(engineEnvironmentSettings).GetAwaiter().GetResult();
}

#pragma warning disable CS1998
/// <summary>
/// Returns the list of initialized <see cref="ITemplateConstraint"/>s.
/// Only returns the list of <see cref="ITemplateConstraint"/> that were initialized successfully.
Expand All @@ -40,45 +35,17 @@ public TemplateConstraintManager(IEngineEnvironmentSettings engineEnvironmentSet
public async Task<IReadOnlyList<ITemplateConstraint>> GetConstraintsAsync(IEnumerable<ITemplateInfo>? templates = null, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
IEnumerable<(string Type, Task<ITemplateConstraint> Task)> constraintsToInitialize;
if (templates?.Any() ?? false)
{
List<string> uniqueConstraints = templates.SelectMany(ti => ti.Constraints.Select(c => c.Type)).Distinct().ToList();
constraintsToInitialize = _templateConstrains.Where(kvp => uniqueConstraints.Contains(kvp.Key)).Select(kvp => (kvp.Key, kvp.Value));
}
else
{
constraintsToInitialize = _templateConstrains.Select(kvp => (kvp.Key, kvp.Value));
}

try
{
_logger.LogDebug($"Waiting for {constraintsToInitialize.Count()} to be initialized.");
await CancellableWhenAll(constraintsToInitialize.Select(c => c.Task), cancellationToken).ConfigureAwait(false);
_logger.LogDebug($"{constraintsToInitialize.Count()} constraints were initialized.");
return constraintsToInitialize.Select(c => c.Task.Result).ToList();
}
catch (TaskCanceledException)
var uniqueConstraints = templates?.SelectMany(ti => ti.Constraints.Select(c => c.Type)).Distinct() ?? _templateConstraints.Keys;
List<ITemplateConstraint> templateConstraints = [];
foreach (var constraint in uniqueConstraints)
{
throw;
}
catch (Exception)
{
foreach (var constraint in constraintsToInitialize)
if (_templateConstraints.TryGetValue(constraint, out var result))
{
if (constraint.Task.IsFaulted || constraint.Task.IsCanceled)
{
_logger.LogWarning(LocalizableStrings.TemplateConstraintManager_Error_FailedToInitialize, constraint.Type, constraint.Task.Exception.Message);
_logger.LogDebug($"Details: {constraint.Task.Exception}.");
}
templateConstraints.Add(result);
}
_logger.LogDebug($"{constraintsToInitialize.Count(c => c.Task.Status == TaskStatus.RanToCompletion)} constraints were initialized.");
return constraintsToInitialize
.Where(c => c.Task.Status == TaskStatus.RanToCompletion)
.Select(c => c.Task.Result)
.ToList();
}

return templateConstraints;
}

/// <summary>
Expand All @@ -91,50 +58,36 @@ public async Task<IReadOnlyList<ITemplateConstraint>> GetConstraintsAsync(IEnume
public async Task<TemplateConstraintResult> EvaluateConstraintAsync(string type, string? args, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (!_templateConstrains.TryGetValue(type, out Task<ITemplateConstraint> task))
if (_evaluatedConstraints.TryGetValue((type, args), out TemplateConstraintResult result))
{
_logger.LogDebug($"The constraint '{type}' is unknown.");
return TemplateConstraintResult.CreateInitializationFailure(type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_UnknownType, type));
return result;
}

if (!task.IsCompleted)
if (!_templateConstraints.TryGetValue(type, out ITemplateConstraint constraint))
{
try
if (_evaluatedConstraints.TryGetValue((type, null), out result))
{
_logger.LogDebug($"The constraint '{type}' is not initialized, waiting for initialization.");
await CancellableWhenAll(new[] { task }, cancellationToken).ConfigureAwait(false);
_logger.LogDebug($"The constraint '{type}' is initialized successfully.");
return result;
}
catch (TaskCanceledException)
{
throw;
}
catch (Exception)
{
//handled below
}
}

cancellationToken.ThrowIfCancellationRequested();

if (task.IsFaulted || task.IsCanceled)
{
var exception = task.Exception is not null ? task.Exception.InnerException ?? task.Exception : task.Exception;
_logger.LogDebug($"The constraint '{type}' failed to be initialized, details: {exception}.");
return TemplateConstraintResult.CreateInitializationFailure(type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToInitialize, type, exception?.Message));
_logger.LogDebug($"The constraint '{type}' is unknown.");
return TemplateConstraintResult.CreateInitializationFailure(type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_UnknownType, type));
}

try
{
return task.Result.Evaluate(args);
result = constraint.Evaluate(args);
_evaluatedConstraints.Add((type, args), result);
return result;
}
catch (Exception e)
{
_logger.LogDebug($"The constraint '{type}' failed to be evaluated for the args '{args}', details: {e}.");
return TemplateConstraintResult.CreateEvaluationFailure(task.Result, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToEvaluate, type, args, e.Message));
return TemplateConstraintResult.CreateEvaluationFailure(constraint, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToEvaluate, type, args, e.Message));
}

}
#pragma warning restore CS1998

/// <summary>
/// Evaluates the constraints with given <paramref name="templates"/>.
Expand All @@ -146,73 +99,19 @@ public async Task<TemplateConstraintResult> EvaluateConstraintAsync(string type,
public async Task<IReadOnlyList<(ITemplateInfo Template, IReadOnlyList<TemplateConstraintResult> Result)>> EvaluateConstraintsAsync(IEnumerable<ITemplateInfo> templates, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

var requiredConstraints = templates.SelectMany(t => t.Constraints).Select(c => c.Type).Distinct();
var tasksToWait = new List<Task>();
foreach (var constraintType in requiredConstraints)
List<(ITemplateInfo Template, IReadOnlyList<TemplateConstraintResult> Result)> list = [];
foreach (var template in templates)
{
if (!_templateConstrains.TryGetValue(constraintType, out Task<ITemplateConstraint> task))
List<TemplateConstraintResult> results = [];
foreach (var constraint in template.Constraints)
{
//handled below
continue;
results.Add(await EvaluateConstraintAsync(constraint.Type, constraint.Args, cancellationToken).ConfigureAwait(false));
}
tasksToWait.Add(task);
}

if (tasksToWait.Any(t => !t.IsCompleted))
{
try
{
var notCompletedTasks = tasksToWait.Where(t => !t.IsCompleted);
_logger.LogDebug($"The constraint(s) are not initialized, waiting for initialization.");
await CancellableWhenAll(notCompletedTasks, cancellationToken).ConfigureAwait(false);
_logger.LogDebug($"The constraint(s) are initialized successfully.");
}
catch (TaskCanceledException)
{
throw;
}
catch (Exception)
{
//handled below
}
list.Add((template, results));
}
cancellationToken.ThrowIfCancellationRequested();

List<(ITemplateInfo, IReadOnlyList<TemplateConstraintResult>)> evaluationResult = new();
foreach (ITemplateInfo template in templates)
{
List<TemplateConstraintResult> constraintResults = new();
foreach (var constraint in template.Constraints)
{
if (!_templateConstrains.TryGetValue(constraint.Type, out Task<ITemplateConstraint> task))
{
_logger.LogDebug($"The constraint '{constraint.Type}' is unknown.");
constraintResults.Add(TemplateConstraintResult.CreateInitializationFailure(constraint.Type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_UnknownType, constraint.Type)));
continue;
}

if (task.IsFaulted || task.IsCanceled)
{
var exception = task.Exception is not null ? task.Exception.InnerException ?? task.Exception : task.Exception;
_logger.LogDebug($"The constraint '{constraint.Type}' failed to be initialized, details: {exception}.");
constraintResults.Add(TemplateConstraintResult.CreateInitializationFailure(constraint.Type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToInitialize, constraint.Type, exception?.Message)));
continue;
}

try
{
constraintResults.Add(task.Result.Evaluate(constraint.Args));
}
catch (Exception e)
{
_logger.LogDebug($"The constraint '{constraint.Type}' failed to be evaluated for the args '{constraint.Args}', details: {e}.");
constraintResults.Add(TemplateConstraintResult.CreateEvaluationFailure(_templateConstrains[constraint.Type].Result, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToEvaluate, constraint.Type, constraint.Args, e.Message)));
}
}
evaluationResult.Add((template, constraintResults));
}
return evaluationResult;
return list;
}

/// <inheritdoc/>
Expand All @@ -235,5 +134,43 @@ await Task.WhenAny(
//throws exceptions
await Task.WhenAll(tasks).ConfigureAwait(false);
}

private async Task InitializeTemplateConstraints(IEngineEnvironmentSettings engineEnvironmentSettings)
{
var constraintFactories = engineEnvironmentSettings.Components.OfType<ITemplateConstraintFactory>();
_logger.LogDebug($"Found {constraintFactories.Count()} constraints factories, initializing.");
foreach (var constraintFactory in constraintFactories)
{
ITemplateConstraint? constraint = null;
Exception? exception = null;

try
{
constraint = await constraintFactory.CreateTemplateConstraintAsync(engineEnvironmentSettings, _cancellationTokenSource.Token).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (Exception e)
{
//handled below
exception = e;
}

_cancellationTokenSource.Token.ThrowIfCancellationRequested();

if (constraint is null)
{
exception = exception is not null ? exception.InnerException ?? exception : exception;
_logger.LogDebug($"The constraint '{constraintFactory.Type}' failed to be initialized, details: {exception}.");
_evaluatedConstraints.Add((constraintFactory.Type, null), TemplateConstraintResult.CreateInitializationFailure(constraintFactory.Type, string.Format(LocalizableStrings.TemplateConstraintManager_Error_FailedToInitialize, constraintFactory.Type, exception?.Message)));
}
else
{
_templateConstraints[constraintFactory.Type] = constraint;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public LongRunningTestConstraintFactory(string type)

public async Task<ITemplateConstraint> CreateTemplateConstraintAsync(IEngineEnvironmentSettings environmentSettings, CancellationToken cancellationToken)
{
await Task.Delay(30000);
await Task.Delay(3000);
throw new Exception("creation failed");
}
}
Expand Down
Loading