Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 3 Min.

Datenbanken und externe Dienste

Erst bei Datenbanken, Caches und externen APIs zeigt sich, wie belastbar ein Health Check wirklich ist. Von einfachen Statusmeldungen ausgehend erweitern wir die Möglichkeiten bis hin zu Prüfungen, die Abhängigkeiten sichtbar machen und damit helfen, Ausfälle besser einzuordnen.
© EMGenie

Der erste Teil der Serie „Health Checks in ASP.NET richtig nutzen“ hat einen einfachen Health-Endpunkt vorgestellt, der entweder drei unterschiedliche Werte für den Status oder weitere Informationen, etwa im JSON-Format, ausgibt. Der in der Praxis spannende Teil beginnt dort, wo Health Checks Abhängigkeiten wie Datenbanken, Message Broker oder externe HTTP-APIs überwachen. Ziel ist, nicht nur den eigenen Prozess, sondern das gesamte System aus Sicht des Clients zu betrachten: Wenn die Datenbank nicht erreichbar ist, ist der Service aus Nutzersicht faktisch down.

ASP.NET Core bringt mit IHealthCheck eine einfache Schnittstelle mit, über die sich eigene Prüfungen implementieren lassen. Zur Erinnerung: Teil 1 dieser Serie hat ein eine einfache Klasse SampleHealthCheck (siehe Listing 1) gezeigt, die dieses Interface implementiert.

Listing 1: Implementierung des IHealthCheck Interface
public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        var isHealthy = true; // Prüflogik...
        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("Alles in Ordnung"));
        }
        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus,
                "Ein Fehler ist aufgetreten"));
    }
} 

Die Prüflogik ist hier allerdings noch auf den Standardwert true festgelegt, übernimmt aber noch keine wirkliche Prüfung. Dieses Beispiel lässt sich nun auf andere Bereiche erweitern. Ein typischer Datenbank-Check etwa könnte aussehen wie in Listing 2 gezeigt.

Listing 2: Implementierung eines beispielhaften Datenbank-Checks
public class DatabaseHealthCheck : IHealthCheck
{
    private readonly IConfiguration _config;
    public DatabaseHealthCheck(IConfiguration config) => _config = config;
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        var connectionString = _config.GetConnectionString("DefaultConnection");
        try
        {
            await using var connection = new SqlConnection(connectionString);
            await connection.OpenAsync(cancellationToken);
            // Optional: einfache Abfrage, um Latenz / Timeouts zu erkennen
            using var cmd = connection.CreateCommand();
            cmd.CommandText = "SELECT 1";
            await cmd.ExecuteScalarAsync(cancellationToken);
            return HealthCheckResult.Healthy("Database reachable");
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy("Database unreachable", ex);
        }
    }
} 

Registriert wird dieser Check bei AddHealthChecks, idealerweise mit einem sprechenden Namen zur besseren Identifikation:

 

builder.Services.AddHealthChecks()
    .AddCheck<DatabaseHealthCheck>("sql_db");

 

Für viele Standard-Abhängigkeiten existieren zudem fertige Checks, sowohl in Microsoft-Paketen als auch in Bibliotheken wie AspNetCore.Diagnostics.HealthChecks. Dazu zählen Pakete für beispielsweise SQL Server, PostgreSQL, Redis, MongoDB wie AspNetCore.HealthChecks.SqlServer, AspNetCore.HealthChecks.Npgsql (PostgreSQL) und AspNetCore.HealthChecks.Redis. Damit lässt sich eine typische Infrastruktur sehr schnell abbilden:

 

var sqlServerConnection = builder.Configuration.GetConnectionString("SqlServerConnection") ?? "SqlServerDefaultConnection";
var redisConnection = builder.Configuration.GetConnectionString("RedisConnection") ?? "RedisDefaultConnection";
builder.Services.AddHealthChecks()
    .AddSqlServer(sqlServerConnection)
    .AddRedis(redisConnection)
    .AddCheck<ExternalApiHealthCheck>("external_api");

 

Wer mehr Einfluss beim Hinzufügen dieser Health Checks haben möchte, kann das über weitere Parameter bei AddSqlServer und AddRedis erledigen, wie Listing 3 zeigt.

Listing 3: Konfiguration von Health Checks mit Parametern
builder.Services.AddHealthChecks()
    .AddSqlServer(
        connectionString: builder.Configuration.GetConnectionString("DefaultConnection")!,
        name: "sqlserver",
        failureStatus: HealthStatus.Unhealthy,
        tags: new[] { "database", "sql" })
    .AddRedis(
        redisConnectionString: builder.Configuration.GetConnectionString("Redis")!,
        name: "redis",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "cache", "redis" }); 

Ein externer API-Check sollte dabei immer mit Time-outs und gegebenenfalls Cancellation-Tokens arbeiten, damit der Health-Endpunkt selbst nicht blockiert. Listing 4 zeigt die Implementierung einer eigenen Health-Check-Klasse für externe APIs.

Listing 4: Health-Check-Implementierung für einen externen Dienst
public class ExternalApiHealthCheck : IHealthCheck
{
    private readonly HttpClient _client;
    public ExternalApiHealthCheck(HttpClient client) => _client = client;
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        cts.CancelAfter(TimeSpan.FromSeconds(2));
        try
        {
            var response = await _client.GetAsync("/ping", cts.Token);
            if (response.IsSuccessStatusCode)
                return HealthCheckResult.Healthy("External API reachable");
            return HealthCheckResult.Unhealthy($"External API returned {response.StatusCode}");
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy("External API unreachable", ex);
        }
    }
} 

Wichtig ist die Bewertung: Eine nicht erreichbare optionale Integration kann Degraded sein, während das Wegbrechen der primären Datenbank Unhealthy bedeuten sollte. Durch die unterschiedlichen Statuswerte können Load-Balancer oder Orchestrierungsplattformen differenziert reagieren, indem sie beispielsweise Anfragen drosseln, statt den Pod sofort neu zu starten.

Startup-Health-Check

Bei Anwendungen mit langwierigen Initialisierungsschritten lässt sich eine separate Startup-Probe implementieren. Im Beispiel von Microsoft setzt ein Background-Service nach 15 Sekunden eine Variable StartupCompleted. Die zugehörige StartupHealthCheck-Klasse liefert Healthy, sobald die Initialisierung abgeschlossen ist. Diese Probe wird über Tags nur an den Readiness-Endpunkt gebunden. In Kubernetes wird die Startup-Probe nur während des initialen Hochfahrens ausgeführt.

Zwischenfazit und Ausblick

Dieser Beitrag hat gezeigt, wie sich Datenbanken, Caches und der Speicher im Rahmen von Health Checks überwachen lassen und wie Liveness-, Readiness- und Startup-Proben mithilfe von Tags getrennt werden. Im nächsten Teil dieser Serie wird es um externe APIs, Dateisystem- und Speicherplatzprüfungen sowie um eigene JSON-Antworten für Monitoring-Tools gehen.

Neueste Beiträge

Grundlagen von Health Checks - Health Checks in ASP.NET richtig nutzen, Teil 1
Ein einfacher Statuscode sagt wenig darüber aus, ob eine Anwendung wirklich betriebsbereit ist. ASP.NET bietet dafür mehr Möglichkeiten, als viele /health-Endpunkte vermuten lassen. Genau dort beginnt der Unterschied zwischen Erreichbarkeit und echter Diagnose.
4 Minuten
Figma Dev Mode im Einsatz - UX goes Dev, Teil 3
Der größte Mehrwert des Developer Mode von Figma liegt darin, die Brücke zwischen visuellem Design und qualitativ hochwertigem UI-Code zu schlagen.
7 Minuten
9. Jul 2026

Das könnte Dich auch interessieren

Mit .NET ins Web - Web-Apps mit Blazor, Teil 4
Das UI moderner Webapplikationen rein mit HTML und CSS zu gestalten widerspricht dem Komponentenansatz von Blazor. Drittanbieter wie Syncfusion oder Telerik bieten Abhilfe.
13 Minuten
19. Jul 2021
Grundlagen von Health Checks - Health Checks in ASP.NET richtig nutzen, Teil 1
Ein einfacher Statuscode sagt wenig darüber aus, ob eine Anwendung wirklich betriebsbereit ist. ASP.NET bietet dafür mehr Möglichkeiten, als viele /health-Endpunkte vermuten lassen. Genau dort beginnt der Unterschied zwischen Erreichbarkeit und echter Diagnose.
4 Minuten
Browser-Apps mit Avalonia entwickeln - Avalonia
Klassische UI-Frameworks finden ihren Weg in den Browser
5 Minuten
11. Aug 2025
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige