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.Blueprint.Redis.Configuration;
|
||||||
using Core.Thalos.BuildingBlocks;
|
using Core.Thalos.BuildingBlocks;
|
||||||
using Core.Thalos.BuildingBlocks.Configuration;
|
using Core.Thalos.BuildingBlocks.Configuration;
|
||||||
|
using Core.Thalos.DAL.API.HealthCheck;
|
||||||
|
using Core.Thalos.DAL.API.HealthCheck.Writer;
|
||||||
using Core.Thalos.Provider;
|
using Core.Thalos.Provider;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
using Microsoft.AspNetCore.HttpLogging;
|
using Microsoft.AspNetCore.HttpLogging;
|
||||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json.Serialization;
|
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();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.UseLogging(builder.Configuration);
|
app.UseLogging(builder.Configuration);
|
||||||
@@ -82,6 +101,10 @@ app.UseAuthentication();
|
|||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
app.MapHealthChecks("/health");
|
app.MapHealthChecks("/health", new HealthCheckOptions
|
||||||
|
{
|
||||||
|
ResponseWriter = HealthCheckResponseWriter.WriteResponse,
|
||||||
|
AllowCachingResponses = false
|
||||||
|
});
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
Reference in New Issue
Block a user