using BuildingBlocks.EFCore; using BuildingBlocks.EventStoreDB; using BuildingBlocks.MassTransit; using BuildingBlocks.Mongo; using BuildingBlocks.Web; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using MongoDB.Driver; using RabbitMQ.Client; namespace BuildingBlocks.HealthCheck; public static class Extensions { private const string HealthEndpointPath = "/health"; private const string AlivenessEndpointPath = "/alive"; public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services) { var healthOptions = services.GetOptions(nameof(HealthOptions)); if (healthOptions.Enabled) { var appOptions = services.GetOptions(nameof(AppOptions)); var postgresOptions = services.GetOptions(nameof(PostgresOptions)); var rabbitMqOptions = services.GetOptions(nameof(RabbitMqOptions)); var eventStoreOptions = services.GetOptions(nameof(EventStoreOptions)); var mongoOptions = services.GetOptions(nameof(MongoOptions)); var healthChecksBuilder = services.AddHealthChecks() // Add a default liveness check to ensure app is responsive .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]) .AddRabbitMQ( serviceProvider => { var factory = new ConnectionFactory { Uri = new Uri($"amqp://{rabbitMqOptions.UserName}:{rabbitMqOptions.Password}@{rabbitMqOptions.HostName}"), }; return factory.CreateConnectionAsync(); }); if (!string.IsNullOrEmpty(mongoOptions.ConnectionString)) { healthChecksBuilder.AddMongoDb( clientFactory: _ => new MongoClient(mongoOptions.ConnectionString), name: "MongoDB-Health", failureStatus: HealthStatus.Unhealthy, timeout: TimeSpan.FromSeconds(10)); } if (!string.IsNullOrEmpty(postgresOptions.ConnectionString)) healthChecksBuilder.AddNpgSql(postgresOptions.ConnectionString); if (!string.IsNullOrEmpty(eventStoreOptions.ConnectionString)) healthChecksBuilder.AddEventStore(eventStoreOptions.ConnectionString); services.AddHealthChecksUI(setup => { setup.SetEvaluationTimeInSeconds(60); // time in seconds between check setup.AddHealthCheckEndpoint($"Self Check - {appOptions.Name}", HealthEndpointPath); }).AddInMemoryStorage(); } services.AddHealthChecks().AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); return services; } public static WebApplication UseCustomHealthCheck(this WebApplication app) { var healthOptions = app.Configuration.GetOptions(nameof(HealthOptions)); if (app.Environment.IsDevelopment()) { app.MapHealthChecks(HealthEndpointPath); app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions { Predicate = r => r.Tags.Contains("live"), }); } if (healthOptions.Enabled) app.MapHealthChecksUI(options => options.UIPath = "/health-ui"); return app; } }