Add health
This commit is contained in:
		| @@ -0,0 +1,31 @@ | ||||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||||
| using MongoDB.Bson; | ||||
| using MongoDB.Driver; | ||||
|  | ||||
| namespace Core.Thalos.DAL.API.HealthCheck | ||||
| { | ||||
|     public class MongoConnectionHealthCheck(string connectionString, string databaseName) : IHealthCheck | ||||
|     { | ||||
|  | ||||
|         public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             var settings = MongoClientSettings.FromConnectionString(connectionString); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 var mongoClient = new MongoClient(settings); | ||||
|  | ||||
|                 var database = mongoClient.GetDatabase(databaseName); | ||||
|                 var command = new BsonDocument("ping", 1); | ||||
|  | ||||
|                 await database.RunCommandAsync<BsonDocument>(command); | ||||
|  | ||||
|                 return HealthCheckResult.Healthy($"MongoDB is healthy, {databaseName} database from {settings.Server} is reachable."); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return HealthCheckResult.Degraded($"MongoDB is Degraded, {databaseName} database from {settings?.Server?.Host} is unreachable.", ex); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||||
| using StackExchange.Redis; | ||||
|  | ||||
| public sealed class RedisConnectionHealthCheck : IHealthCheck | ||||
| { | ||||
|     private readonly string _connectionString; | ||||
|     public RedisConnectionHealthCheck(string connectionString) => _connectionString = connectionString; | ||||
|  | ||||
|     public async Task<HealthCheckResult> CheckHealthAsync( | ||||
|         HealthCheckContext context, | ||||
|         CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var options = ConfigurationOptions.Parse(_connectionString); | ||||
|             options.AbortOnConnectFail = false; | ||||
|             options.ConnectTimeout = 2000;   // optional, be snappy | ||||
|  | ||||
|             using var mux = await ConnectionMultiplexer.ConnectAsync(options); | ||||
|             if (!mux.IsConnected) return HealthCheckResult.Unhealthy("Redis not connected."); | ||||
|  | ||||
|             var ping = await mux.GetDatabase().PingAsync(); | ||||
|             return HealthCheckResult.Healthy($"Redis OK (ping {ping.TotalMilliseconds:N0} ms)"); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return HealthCheckResult.Unhealthy("Redis check failed.", ex); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||||
| using System.Text.Json; | ||||
|  | ||||
| namespace Core.Thalos.DAL.API.HealthCheck.Writer | ||||
| { | ||||
|     public static class HealthCheckResponseWriter | ||||
|     { | ||||
|         public static Task WriteResponse(HttpContext context, HealthReport result) | ||||
|         { | ||||
|             context.Response.ContentType = "application/json"; | ||||
|  | ||||
|             context.Response.StatusCode = result.Status switch | ||||
|             { | ||||
|                 HealthStatus.Healthy => StatusCodes.Status200OK, | ||||
|                 HealthStatus.Degraded => StatusCodes.Status500InternalServerError, | ||||
|                 HealthStatus.Unhealthy => StatusCodes.Status503ServiceUnavailable, | ||||
|                 _ => StatusCodes.Status500InternalServerError | ||||
|             }; | ||||
|  | ||||
|             var options = new JsonSerializerOptions | ||||
|             { | ||||
|                 WriteIndented = true, | ||||
|                 PropertyNamingPolicy = JsonNamingPolicy.CamelCase | ||||
|             }; | ||||
|  | ||||
|             var json = new | ||||
|             { | ||||
|                 status = result.Status.ToString(), | ||||
|                 services = result.Entries.Select(e => new | ||||
|                 { | ||||
|                     key = e.Key, | ||||
|                     status = e.Value.Status.ToString(), | ||||
|                     description = e.Value.Description ?? string.Empty, | ||||
|                     exception = e.Value.Exception?.Message, | ||||
|                     duration = e.Value.Duration.ToString(), | ||||
|  | ||||
|                     statusCode = e.Value.Status switch | ||||
|                     { | ||||
|                         HealthStatus.Healthy => StatusCodes.Status200OK, | ||||
|                         HealthStatus.Degraded => StatusCodes.Status500InternalServerError, | ||||
|                         HealthStatus.Unhealthy => StatusCodes.Status503ServiceUnavailable, | ||||
|                         _ => StatusCodes.Status500InternalServerError | ||||
|                     } | ||||
|                 }) | ||||
|             }; | ||||
|  | ||||
|             return context.Response.WriteAsync(JsonSerializer.Serialize(json, options)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -4,8 +4,12 @@ using Core.Blueprint.Logging.Configuration; | ||||
| using Core.Blueprint.Redis.Configuration; | ||||
| using Core.Thalos.BuildingBlocks; | ||||
| using Core.Thalos.BuildingBlocks.Configuration; | ||||
| using Core.Thalos.DAL.API.HealthCheck; | ||||
| using Core.Thalos.DAL.API.HealthCheck.Writer; | ||||
| using Core.Thalos.Provider; | ||||
| using Microsoft.AspNetCore.Diagnostics.HealthChecks; | ||||
| using Microsoft.AspNetCore.HttpLogging; | ||||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||||
| using System.Reflection; | ||||
| using System.Text.Json.Serialization; | ||||
|  | ||||
| @@ -64,6 +68,21 @@ builder.Host.ConfigureServices((context, services) => | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| // Add health checks | ||||
| builder.Services.AddHealthChecks() | ||||
|     .AddCheck( | ||||
|         "mongodb", | ||||
|         new MongoConnectionHealthCheck( | ||||
|             connectionString: builder.Configuration.GetConnectionString("MongoDB")!, | ||||
|             databaseName: builder.Configuration.GetSection("MongoDb:DatabaseName").Value!), | ||||
|         failureStatus: HealthStatus.Unhealthy, | ||||
|         tags: new[] { "db", "mongo" }) | ||||
|     .AddCheck( | ||||
|         "redis", | ||||
|         new RedisConnectionHealthCheck(builder.Configuration.GetConnectionString("Redis")!), | ||||
|         failureStatus: HealthStatus.Unhealthy, | ||||
|         tags: new[] { "db", "redis" }); | ||||
|  | ||||
| var app = builder.Build(); | ||||
|  | ||||
| app.UseLogging(builder.Configuration); | ||||
| @@ -82,6 +101,10 @@ app.UseAuthentication(); | ||||
| app.UseAuthorization(); | ||||
|  | ||||
| app.MapControllers(); | ||||
| app.MapHealthChecks("/health"); | ||||
| app.MapHealthChecks("/health", new HealthCheckOptions | ||||
| { | ||||
|     ResponseWriter = HealthCheckResponseWriter.WriteResponse, | ||||
|     AllowCachingResponses = false | ||||
| }); | ||||
|  | ||||
| app.Run(); | ||||
		Reference in New Issue
	
	Block a user