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