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

Gebaut für lange Läufe - Kimi K3 – das Modell hinter dem Agenten, Teil 1
Kimi K3 kombiniert 2,8 Billionen Parameter, native Bildverarbeitung und ein Kontextfenster mit einer Million Token. Das sind tolle Zahlen. Seine Besonderheit liegt aber darin, dass Architektur, Training und Laufzeitumgebung auf Agenten zielen, die über viele Schritte handeln, Werkzeuge aufrufen und Ergebnisse prüfen.
6 Minuten
Zwei Konferenz-Openings, eine Sprecherin – wie aus einem Terminkonflikt ein KI-Usecase wurde - Making-of eines Avatars mit HeyGen und ElevenLabs
Ein Terminkonflikt gelöst von einem digitalen Zwilling. Die Ebner Media Group hat die erste Infinite AI Conference von einem Avatar eröffnen lassen. Ein Erfahrungsbericht über den Produktionsprozess und den echten Nutzen synthetischer Präsenz.
7 Minuten
12. Aug 2026
Die Kunst der langen Aufgabenläufe - Kimi K3 – das Modell hinter dem Agenten, Teil 2
Ein guter Code-Generator löst eine klar umrissene Funktion. Ein Coding-Agent muss dagegen ein Repository erkunden, Hypothesen bilden, Werkzeuge auswählen, Tests auswerten und nach Fehlschlägen den Kurs ändern. Kimi K3 zielt auf diese zweite Klasse von Aufgaben.
8 Minuten

Das könnte Dich auch interessieren

Health Checks für Ressourcen - Health Checks in ASP.NET richtig nutzen, Teil 3
Wenn externe APIs stocken, Speicher knapp wird oder Ressourcen an Grenzen laufen, reicht ein grüner Gesamtstatus nicht mehr aus. Wie Health Checks näher an die tatsächlichen Betriebsrisiken heranrücken, ohne den Diagnose-Endpunkt unnötig aufzublähen.
4 Minuten
Health Checks und Kubernetes - Health Checks in ASP.NET richtig nutzen, Teil 4
In Kubernetes entscheidet ein Health Check nicht nur über Sichtbarkeit im Monitoring, sondern auch darüber, ob Traffic fließt oder ein Container neu startet. Hier zeigen wir, warum saubere Grenzen zwischen Liveness und Readiness in produktiven ASP.NET-Anwendungen so wichtig sind.
4 Minuten
Die Chromium-Engine anbinden - Ein eigenes Steuerelement für Webinhalte, Teil 14
Das Browser-Control wird für den Einbau der Chromium-Engine vorbereitet.
10 Minuten
17. Okt 2022
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige