From db8d3217ce87f84295a2954e2f1f395bfd446af2 Mon Sep 17 00:00:00 2001 From: Collin Barrett <6483057+collinbarrett@users.noreply.github.com> Date: Mon, 26 May 2025 17:40:52 -0500 Subject: [PATCH] Revert "refactor(api): tidy Aspire configs" This reverts commit 5d26e67555d9df0bce3744031655776065ac26b3. --- .../FilterLists.Directory.Api/Program.cs | 11 +++ .../FilterLists.ServiceDefaults/Extensions.cs | 69 ++++++++++++------- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/services/Directory/FilterLists.Directory.Api/Program.cs b/services/Directory/FilterLists.Directory.Api/Program.cs index 5182d8778..2618a16da 100644 --- a/services/Directory/FilterLists.Directory.Api/Program.cs +++ b/services/Directory/FilterLists.Directory.Api/Program.cs @@ -5,11 +5,17 @@ var builder = WebApplication.CreateBuilder(args); builder.WebHost.ConfigureKestrel(serverOptions => serverOptions.AddServerHeader = false); + +// for health checks: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/health-checks#non-development-environments +builder.Services.AddRequestTimeouts(); +builder.Services.AddOutputCache(); + builder.AddServiceDefaults(); builder.Services.AddCors(CorsConfiguration.SetupAction); builder.Services.AddProblemDetails(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(OpenApiGenConfiguration.SetupAction); + builder.AddApplication(); var app = builder.Build(); @@ -17,6 +23,11 @@ app.UseExceptionHandler(); app.UseCors(); app.MapEndpoints(); + +// for health checks: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/health-checks#non-development-environments +app.UseRequestTimeouts(); +app.UseOutputCache(); + app.MapDefaultEndpoints(); app.UseSwagger(o => o.RouteTemplate = "{documentName}/openapi.json"); app.UseSwaggerUI(SwaggerUiConfiguration.SetupAction); diff --git a/services/FilterLists.ServiceDefaults/Extensions.cs b/services/FilterLists.ServiceDefaults/Extensions.cs index 0eaa3adcb..0f1b3d23f 100644 --- a/services/FilterLists.ServiceDefaults/Extensions.cs +++ b/services/FilterLists.ServiceDefaults/Extensions.cs @@ -12,23 +12,32 @@ // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.Hosting; +// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults public static class Extensions { private const string HealthEndpointPath = "/health"; private const string AlivenessEndpointPath = "/alive"; - private const string HealthCheckPolicyName = "HealthChecks"; public static void AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.ConfigureOpenTelemetry(); + builder.AddDefaultHealthChecks(); + builder.Services.AddServiceDiscovery(); + builder.Services.ConfigureHttpClientDefaults(http => { + // Turn on resilience by default http.AddStandardResilienceHandler(); + + // Turn on service discovery by default http.AddServiceDiscovery(); }); + // restrict the allowed schemes for service discovery builder.Services.Configure(options => options.AllowedSchemes = ["https"]); } @@ -42,19 +51,26 @@ private static void ConfigureOpenTelemetry(this TBuilder builder) wher builder.Services.AddOpenTelemetry() .WithMetrics(metrics => + { metrics.AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() - .AddRuntimeInstrumentation()) + .AddRuntimeInstrumentation(); + }) .WithTracing(tracing => + { tracing.AddSource(builder.Environment.ApplicationName) .AddAspNetCoreInstrumentation(tracingOptions => + // Exclude health check requests from tracing tracingOptions.Filter = context => !context.Request.Path.StartsWithSegments(HealthEndpointPath, StringComparison.InvariantCultureIgnoreCase) && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath, StringComparison.InvariantCultureIgnoreCase) ) - .AddHttpClientInstrumentation()); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); builder.AddOpenTelemetryExporters(); } @@ -62,46 +78,53 @@ private static void ConfigureOpenTelemetry(this TBuilder builder) wher private static void AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder { - if (!string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"])) - builder.Services.AddOpenTelemetry().UseOtlpExporter(); + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); - if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) - builder.Services.AddOpenTelemetry().UseAzureMonitor(); + if (useOtlpExporter) builder.Services.AddOpenTelemetry().UseOtlpExporter(); + + // enable the Azure Monitor exporter + if (!builder.Environment.IsDevelopment()) + { + if (string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + throw new InvalidOperationException("APPLICATIONINSIGHTS_CONNECTION_STRING is not set."); + + builder.Services.AddOpenTelemetry() + .UseAzureMonitor(); + } } // https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/health-checks#non-development-environments private static void AddDefaultHealthChecks(this IHostApplicationBuilder builder) { - builder.Services.AddRequestTimeouts(); - builder.Services.AddOutputCache(); - builder.Services.AddRequestTimeouts(static timeouts => - timeouts.AddPolicy(HealthCheckPolicyName, TimeSpan.FromSeconds(5))); + timeouts.AddPolicy("HealthChecks", TimeSpan.FromSeconds(5))); builder.Services.AddOutputCache(static caching => - caching.AddPolicy(HealthCheckPolicyName, static policy => policy.Expire(TimeSpan.FromSeconds(10)))); + caching.AddPolicy("HealthChecks", + static policy => policy.Expire(TimeSpan.FromSeconds(10)))); builder.Services.AddHealthChecks() + // Add a default liveness check to ensure the app is responsive .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); } - // https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/health-checks#non-development-environments public static void MapDefaultEndpoints(this WebApplication app) { - app.UseRequestTimeouts(); - app.UseOutputCache(); - var healthChecks = app.MapGroup(""); healthChecks - .CacheOutput(HealthCheckPolicyName) - .WithRequestTimeout(HealthCheckPolicyName); + .CacheOutput("HealthChecks") + .WithRequestTimeout("HealthChecks"); - healthChecks.MapHealthChecks(HealthEndpointPath).DisableHttpMetrics(); + // All health checks must pass for the app to be + // considered ready to accept traffic after starting + healthChecks.MapHealthChecks(HealthEndpointPath); + + // Only health checks tagged with the "live" tag + // must pass for the app to be considered alive healthChecks.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions - { - Predicate = static r => r.Tags.Contains("live") - }) - .DisableHttpMetrics(); + { + Predicate = static r => r.Tags.Contains("live") + }); } } \ No newline at end of file