Skip to content

Change tests to use WaitForResourceHealthy #705

@DamianEdwards

Description

@DamianEdwards

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");
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions