-
Notifications
You must be signed in to change notification settings - Fork 305
Open
Labels
Description
From PR comment #521 (comment)
/// <summary>
/// Waits for all resources in the application to become healthy.
/// </summary>
public static async Task WaitForResourcesHealthyAsync(this DistributedApplication app, CancellationToken cancellationToken = default)
{
var logger = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(WaitForResourcesAsync));
var applicationModel = app.Services.GetRequiredService<DistributedApplicationModel>();
var resourceNotificationService = app.Services.GetRequiredService<ResourceNotificationService>();
var resourceTasks = new Dictionary<string, Task<(string Name, string State)>>();
foreach (var resource in applicationModel.Resources)
{
resourceTasks[resource.Name] = GetResourceWaitTask(resource.Name, cancellationToken);
}
logger.LogInformation("Waiting for resources [{Resources}] to become healthy.", string.Join(',', resourceTasks.Keys));
while (resourceTasks.Count > 0)
{
var completedTask = await Task.WhenAny(resourceTasks.Values);
var (completedResourceName, targetStateReached) = await completedTask;
if (targetStateReached == KnownResourceStates.FailedToStart)
{
throw new DistributedApplicationException($"Resource '{completedResourceName}' failed to start.");
}
resourceTasks.Remove(completedResourceName);
logger.LogInformation("Wait for resource '{ResourceName}' completed with state '{ResourceState}'",
completedResourceName, targetStateReached);
// Ensure resources being waited on still exist
var remainingResources = resourceTasks.Keys.ToList();
for (var i = remainingResources.Count - 1; i > 0; i--)
{
var name = remainingResources[i];
if (!applicationModel.Resources.Any(r => r.Name == name))
{
logger.LogInformation("Resource '{ResourceName}' was deleted while waiting for it.", name);
resourceTasks.Remove(name);
remainingResources.RemoveAt(i);
}
}
if (resourceTasks.Count > 0)
{
logger.LogInformation("Still waiting for resources [{Resources}] to become healthy.",
string.Join(',', remainingResources));
}
}
logger.LogInformation("Wait for all resources completed successfully!");
async Task<(string Name, string State)> GetResourceWaitTask(string resourceName, CancellationToken cancellationToken)
{
var resourceEvent = await resourceNotificationService.WaitForResourceHealthyAsync(resourceName, cancellationToken);
return (resourceName, resourceEvent.Snapshot?.State?.Text ?? "Unknown");
}
}