Partager via


Contrôles d’intégrité dans ASP.NET Core

Par Glenn Condron et Juergen Gutsch

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

ASP.NET Core met à disposition un intergiciel de contrôle d’intégrité et des bibliothèques afin de créer des rapports sur l’intégrité des composants d’une infrastructure d’application.

Les contrôles d’intégrité sont exposés par une application comme des points de terminaison HTTP. Les points de terminaison du contrôle d’intégrité peuvent être configurés pour divers scénarios de surveillance en temps réel :

  • Les sondes d’intégrité peuvent être utilisées par les orchestrateurs de conteneurs et les équilibreurs de charge afin de vérifier l’état d’une application. Par exemple, un orchestrateur de conteneurs peut répondre à un résultat de non intégrité en arrêtant le déploiement ou en redémarrant un conteneur. Face à une application non saine, l’équilibreur de charge peut réagir en redirigeant le trafic vers une instance saine.
  • L’utilisation de la mémoire, des disques et des autres ressources de serveur physique peut être supervisée dans le cadre d’un contrôle d’intégrité.
  • Les contrôles d’intégrité peuvent tester les dépendances d’une application, telles que les bases de données et les points de terminaison de service externes, dans le but de vérifier leur disponibilité et leur bon fonctionnement.

Les contrôles d’intégrité sont généralement utilisés avec un service de surveillance externe ou un orchestrateur de conteneurs pour vérifier l’état d’une application. Avant d’ajouter des contrôles d’intégrité à une application, vous devez décider du système de supervision à utiliser. Le système de supervision détermine les types de contrôles d’intégrité qui doivent être créés ainsi que la configuration de leurs points de terminaison.

Sondage d’intégrité de base

Pour de nombreuses applications, un sondage d’intégrité de base qui signale la disponibilité d’une application pour le traitement des requêtes (liveness) suffit à découvrir l’état de l’application.

La configuration de base enregistre les services de contrôle d’intégrité, puis appelle l’intergiciel de contrôle d’intégrité pour répondre à un point de terminaison d’URL avec une réponse sur l’intégrité. Par défaut, aucun contrôle d’intégrité n’est inscrit pour tester les dépendances ou le sous-système. L’application est considérée comme saine si elle est capable de répondre à l’URL de point de terminaison d’intégrité. L’enregistreur de réponses par défaut écrit HealthStatus comme réponse en texte brut au client. Le HealthStatus est HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Program.cs. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks.

L’exemple suivant crée un point de terminaison de contrôle d’intégrité sur /healthz :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker fournit une directive HEALTHCHECK intégrée qui peut être utilisée pour vérifier l’état d’une application utilisant la configuration de contrôle d’intégrité de base :

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

L’exemple précédent utilise curl pour envoyer une requête HTTP au point de terminaison de contrôle d’intégrité à /healthz. curl n’est pas inclus dans les images conteneur Linux .NET, mais il peut être ajouté par l’installation le package requis dans le Dockerfile. Les conteneurs qui utilisent des images basées sur Alpine Linux peuvent utiliser le wget inclus à la place de curl.

Créer des contrôles d’intégrité

Les contrôles d’intégrité sont créés via l’implémentation de l’interface IHealthCheck. La méthode CheckHealthAsync retourne un HealthCheckResult qui indique l’état d’intégrité comme étant Healthy, Degraded ou Unhealthy. Le résultat est écrit sous forme de réponse en texte brut avec un code d’état configurable. La configuration est décrite dans la section Options de contrôle d’intégrité. HealthCheckResult peut également retourner des paires clé-valeur facultatives.

L’exemple suivant montre la disposition d’un contrôle d’intégrité :

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

La logique du contrôle d’intégrité est placée dans la méthode CheckHealthAsync. L’exemple précédent définit une variable factice, de isHealthy, à true. Si la valeur de isHealthy est définie sur false, l’état HealthCheckRegistration.FailureStatus est retourné.

Si CheckHealthAsync lève une exception durant la vérification, un nouvel état HealthReportEntry est retourné avec son HealthReportEntry.Status défini sur FailureStatus. Cet état est défini par AddCheck (consulter la section Enregistrer les services de contrôle d’intégrité) et inclut l’exception interne qui a provoqué l’échec de la vérification. Description est défini sur le message de l’exception.

Inscrire les services de contrôle d’intégrité

Pour enregistrer un service de contrôle d’intégrité, appelez AddCheck dans Program.cs :

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

La surcharge AddCheck de l’exemple suivant définit l’état d’échec (HealthStatus) de manière à être signalé lorsque le contrôle d’intégrité signale un échec. Si l’état d’échec est défini sur null (par défaut), HealthStatus.Unhealthy est signalé. Cette surcharge est utile pour les créateurs de bibliothèque, dans les cas où l’état d’échec indiqué par la bibliothèque est appliqué par l’application lorsqu’un échec est signalé par le contrôle d’intégrité, si l’implémentation de ce dernier respecte le paramètre.

Les contrôles d’intégrité peuvent être filtrés à l’aide de balises. Les balises sont décrites dans la section Filtrer les contrôles d’intégrité.

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck peut également exécuter une fonction lambda. Dans l’exemple suivant, le contrôle d’intégrité retourne toujours un résultat sain :

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

Appelez AddTypeActivatedCheck pour faire passer des arguments à une implémentation de contrôle d’intégrité. Dans l’exemple suivant, un contrôle d’intégrité activé par type accepte un entier et une chaîne dans son constructeur :

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

Pour enregistrer le contrôle d’intégrité précédent, appelez AddTypeActivatedCheck avec l’entier et la chaîne passés en tant qu’arguments :

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

Utiliser le routage des contrôles d’intégrité

Dans Program.cs, appelez MapHealthChecks sur le générateur de points de terminaison avec l’URL du point de terminaison ou le chemin relatif :

app.MapHealthChecks("/healthz");

Exiger un hôte

Appelez RequireHost pour spécifier un ou plusieurs hôtes autorisés pour le point de terminaison du contrôle d’intégrité. Les hôtes doivent être de type Unicode plutôt que Punycode, et peuvent inclure un port. Lorsqu’aucune collection n’est fournie, tous les hôtes sont acceptés :

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

Pour limiter la réponse du point de terminaison du contrôle d’intégrité à un port spécifique uniquement, spécifiez un port dans l’appel à RequireHost. Cette approche est généralement utilisée dans les environnements de conteneur pour exposer un port aux services de surveillance :

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

Avertissement

L’API qui s’appuie sur l’en-tête d’hôte, comme HttpRequest.Host et RequireHost, est soumise à une usurpation potentielle par les clients.

Pour éviter l’usurpation d’hôte ou de port, utilisez l’une des approches suivantes :

Pour empêcher les clients non autorisés d’usurper le port, appelez RequireAuthorization :

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

Pour plus d’informations, consultez Correspondance de l’hôte dans les itinéraires avec RequireHost.

Exiger une autorisation

Appelez RequireAuthorization pour exécuter l’intergiciel d’autorisation sur le point de terminaison de la requête de contrôle d’intégrité. Une surcharge de RequireAuthorization accepte une ou plusieurs stratégies d’autorisation. Lorsqu’aucune stratégie n’est fournie, la stratégie d’autorisation par défaut est utilisée :

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

Activer les requêtes d’origines différentes

Bien qu’il ne soit pas courant d’exécuter les contrôles d’intégrité manuellement à partir d’un navigateur, l’intergiciel CORS peut être activé en appelant RequireCors sur les points de terminaison du contrôle d’intégrité. La surcharge RequireCors accepte un délégué du générateur de stratégies CORS (CorsPolicyBuilder) ou un nom de stratégie. Pour plus d’informations, consultez Activer les requêtes cross-origin (CORS) dans ASP.NET Core.

Options de contrôle d’intégrité

HealthCheckOptions permet de personnaliser le comportement du contrôle d’intégrité :

Filtrer les contrôles d’intégrité

Par défaut, l’intergiciel de contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui retourne une valeur booléenne à l’option Predicate.

L’exemple suivant filtre les contrôles d’intégrité afin d’exécuter uniquement ceux qui comportent la balise sample :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

Personnaliser le code d’état HTTP

Utilisez ResultStatusCodes pour personnaliser le mappage de l’état d’intégrité aux codes d’état HTTP. Les affectations StatusCodes suivantes sont les valeurs par défaut utilisées par le middleware. Modifiez les valeurs de code d’état selon vos besoins :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

Supprimer les en-têtes de cache

AllowCachingResponses contrôle si l’intergiciel de contrôle d’intégrité ajoute des en-têtes HTTP à une réponse de sonde pour empêcher la mise en cache de la réponse. Si la valeur est false (par défaut), le middleware définit ou substitue les en-têtes Cache-Control, Expires et Pragma afin d’empêcher la mise en cache de la réponse. Si la valeur est true, l’intergiciel ne modifie pas les en-têtes de cache de la réponse :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

Personnaliser la sortie

Pour personnaliser la sortie d’un rapport de contrôle d’intégrité, définissez la propriété HealthCheckOptions.ResponseWriter sur un délégué qui écrit la réponse :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

Le délégué par défaut écrit une réponse minimale constituée de texte en clair, avec la valeur de chaîne HealthReport.Status. Le délégué personnalisé suivant génère une réponse JSON personnalisée à l’aide de System.Text.Json :

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

L’API de contrôle d’intégrité ne fournit pas de prise en charge intégrée pour les formats de retour JSON complexes, car le format est spécifique à votre choix de système de surveillance. Personnalisez la réponse des exemples précédents selon vos besoins. Pour plus d’informations sur la sérialisation JSON avec System.Text.Json, consultez Comment sérialiser et désérialiser JSON dans .NET.

Sonde de base de données

Un contrôle d’intégrité peut spécifier une requête de base de données à exécuter en tant que test booléen pour indiquer si la base de données répond normalement.

AspNetCore.Diagnostics.HealthChecks, une bibliothèque de contrôle d’intégrité pour les applications ASP.NET Core, inclut un contrôle d’intégrité qui s’exécute sur une base de données SQL Server. AspNetCore.Diagnostics.HealthChecks exécute une demande SELECT 1 sur la base de données pour confirmer que la connexion à la base de données est saine.

Avertissement

Lorsque vous vérifiez une connexion de base de données à l’aide d’une requête, choisissez une requête qui est retournée rapidement. L’utilisation d’une requête risque néanmoins d’entraîner une surcharge de la base de données et d’en diminuer les performances. Dans la plupart des cas, il n’est pas nécessaire d’utiliser une requête de test. Il suffit simplement d’établir une connexion à la base de données. Si vous avez besoin d’exécuter une requête, choisissez une requête SELECT simple, telle que SELECT 1.

Pour utiliser ce contrôle d’intégrité de SQL Server, incluez une référence de package au package AspNetCore.HealthChecks.SqlServer NuGet. L’exemple suivant enregistre le contrôle d’intégrité de SQL Server :

var conStr = builder.Configuration.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(conStr))
{
    throw new InvalidOperationException(
                       "Could not find a connection string named 'DefaultConnection'.");
}
builder.Services.AddHealthChecks()
    .AddSqlServer(conStr);

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Sondage DbContext Entity Framework Core

La vérification DbContext confirme que l’application peut communiquer avec la base de données configurée pour un EF CoreDbContext. La vérification DbContext est prise en charge dans les applications qui :

AddDbContextCheck inscrit un contrôle d’intégrité pour un DbContext. Le DbContext est fourni à la méthode en tant que TContext. Une surcharge est disponible pour configurer l’état d’échec, les étiquettes et une requête de test personnalisée.

Par défaut :

  • DbContextHealthCheck appelle la méthode EF Core, CanConnectAsync. Vous pouvez choisir quelle opération doit être exécutée lors du contrôle d’intégrité à l’aide des surcharges de la méthode AddDbContextCheck.
  • Le nom du contrôle d’intégrité correspond à celui du type TContext.

L’exemple suivant enregistre un DbContext et un DbContextHealthCheck associé :

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

Séparer les sondages probe readiness et probe liveness

Dans certains scénarios d’hébergement, une paire de contrôles d’intégrité est utilisée pour déterminer deux états de l’application :

  • La disponibilité indique si l’application s’exécute normalement, sans toutefois être prête à recevoir des requêtes.
  • L’activité indique si une application a cessé de fonctionner et doit être redémarrée.

Examinez l’exemple suivant : une application doit télécharger un fichier de configuration volumineux avant d’être prête à traiter les requêtes. Nous ne souhaitons pas que l’application redémarre si le téléchargement initial échoue, car l’application peut réessayer de télécharger le fichier plusieurs fois. Nous utilisons un probe liveness pour décrire l’activité du processus. Aucune autre vérification n’est exécutée. Nous souhaitons également empêcher l’envoi de requêtes à l’application avant la réussite du téléchargement du fichier de configuration. Nous utilisons un probe readiness pour indiquer un état « non prêt », et ce, jusqu’à ce que le téléchargement ait réussi et que l’application soit prête à recevoir des requêtes.

La tâche en arrière-plan suivante simule un processus de démarrage qui prend environ 15 secondes. Une fois terminée, la tâche définit la propriété StartupHealthCheck.StartupCompleted sur vraie :

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

Le StartupHealthCheck signale l’achèvement de la tâche de démarrage de longue durée et expose la propriété StartupCompleted qui est définie par le service en arrière-plan :

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

Le contrôle d’intégrité est inscrit auprès de AddCheck dans Program.cs en même temps que le service hébergé. Étant donné que le service hébergé doit définir la propriété sur le contrôle d’intégrité, le contrôle d’intégrité est également enregistré dans le conteneur du service en tant que singleton :

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

Pour créer deux points de terminaison de contrôle d’intégrité différents, appelez MapHealthChecks deux fois :

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

L’exemple précédent crée les points de terminaison de contrôle d’intégrité suivants :

  • /healthz/ready pour la vérification de la disponibilité. La vérification de la disponibilité filtre les contrôles d’intégrité pour les éléments avec les balises ready.
  • /healthz/live pour la vérification de l’activité. La vérification de l’activité applique un filtre pour exclure tous les contrôles d’intégrité en retournant false dans le délégué HealthCheckOptions.Predicate. Pour plus d’informations sur le filtrage des contrôles d’intégrité, consultez la section Filtrer les contrôles d’intégrité dans cet article.

Avant l’achèvement de la tâche de démarrage, le point de terminaison /healthz/ready signale un état Unhealthy. Une fois la tâche de démarrage achevée, ce point de terminaison signale un état Healthy. Le point de terminaison /healthz/live exclut tous les contrôles et signale un état Healthy pour tous les appels.

Exemple Kubernetes

Dans un environnement tel que Kubernetes, il peut être utile d’utiliser séparément le test permettant de savoir si la l’application est prête et celui visant à savoir si l’application est active. Dans Kubernetes, une application peut devoir exécuter une tâche de démarrage de longue durée avant d’accepter des requêtes, telle qu’un test de la disponibilité de la base de données sous-jacente. L’utilisation séparée des deux tests permet à l’orchestrateur de faire la distinction entre une application qui fonctionne mais qui n’est pas encore prête, et une application qui n’a pas pu démarrer. Pour plus d’informations sur les sondages probe readiness et probe liveness dans Kubernetes, consultez Configure Liveness and Readiness Probes dans la documentation Kubernetes.

L’exemple suivant montre une configuration probe readiness Kubernetes :

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Distribuer une bibliothèque de contrôle d’intégrité

Pour distribuer une bibliothèque comme un contrôle d’intégrité :

  1. Écrivez un contrôle d’intégrité qui implémente l’interface IHealthCheck comme une classe autonome. La classe peut utiliser une injection de dépendance, une activation de type et des options nommées pour accéder aux données de configuration.

  2. Écrivez une méthode d’extension avec des paramètres que l’application consommatrice appelle dans sa méthode Program.cs. Envisagez l’exemple de contrôle d’intégrité suivant, qui accepte arg1 et arg2 en tant que paramètres de constructeur :

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    La signature précédente indique que le contrôle d’intégrité nécessite des données personnalisées pour traiter la logique du probe de contrôle d’intégrité. Les données sont fournies au délégué qui est utilisé pour créer l’instance de contrôle d’intégrité lorsque le contrôle d’intégrité est inscrit avec une méthode d’extension. Dans l’exemple qui suit, l’appelant spécifie les éléments suivants :

    • arg1 : point de données entier du contrôle d’intégrité.
    • arg2 : argument de chaîne pour le contrôle d’intégrité.
    • name : nom de contrôle d’intégrité facultatif. Une valeur par défaut est utilisée pour null.
    • failureStatus : HealthStatus facultatif, signalé pour un état d’échec. Si null, HealthStatus.Unhealthy est utilisé.
    • tags : collection IEnumerable<string> facultative de balises.
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

Serveur de publication des contrôles d’intégrité

Quand un IHealthCheckPublisher est ajouté au conteneur du service, le système de contrôle d’intégrité exécute régulièrement vos contrôles d’intégrité et appelle PublishAsync avec le résultat. Ce processus est utile dans un scénario impliquant un système de surveillance d’intégrité basé sur les envois (push) qui nécessite que chaque processus appelle le système de surveillance régulièrement afin de déterminer l’état d’intégrité.

HealthCheckPublisherOptions vous autorise à définir les éléments suivants :

  • Delay : retard initial appliqué après le démarrage de l’application avant d’exécuter les instances IHealthCheckPublisher. Le retard est appliqué une seule fois au démarrage et ne s’applique pas aux itérations ultérieures. La valeur par défaut est de cinq secondes.
  • Period : période d’exécution de IHealthCheckPublisher. La valeur par défaut est de 30 secondes.
  • Predicate : si Predicate est null (valeur par défaut), le service de publication du contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui filtre l’ensemble de vérifications. Le prédicat est évalué à chaque période.
  • Timeout : délai d’attente pour l’exécution des contrôles d’intégrité pour toutes les instances IHealthCheckPublisher. Utilisez InfiniteTimeSpan pour une exécution sans délai d’attente. La valeur par défaut est de 30 secondes.

L’exemple suivant montre la disposition d’un éditeur d’intégrité :

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

La classe HealthCheckPublisherOptions fournit les propriétés de configuration du comportement de l’éditeur de contrôle d’intégrité.

L’exemple suivant enregistre un éditeur de contrôle d’intégrité en tant que singleton et configure HealthCheckPublisherOptions :

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

AspNetCore.Diagnostics.HealthChecks :

  • inclut des éditeurs de plusieurs systèmes, y compris Application Insights.
  • N’est pas géré ni pris en charge par Microsoft.

Vérifications d’intégrité individuelles

Delay et Period peuvent être définis sur chaque HealthCheckRegistration individuellement. Cela est utile lorsque vous souhaitez exécuter des vérifications d’intégrité à une fréquence différente de la période définie dans HealthCheckPublisherOptions.

Le code suivant définit les Delay et Period pour SampleHealthCheck1 :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks()
   .Add(new HealthCheckRegistration(
       name: "SampleHealthCheck1",
       instance: new SampleHealthCheck(),
       failureStatus: null,
       tags: null,
       timeout: default)
   {
       Delay = TimeSpan.FromSeconds(40),
       Period = TimeSpan.FromSeconds(30)
   });

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Injection de dépendances et contrôles d’intégrité

Il est possible d’utiliser l’injection de dépendances pour consommer une instance d’un Type spécifique dans une classe de contrôle d’intégrité. L’injection de dépendances peut être utile pour injecter des options ou une configuration globale dans un contrôle d’intégrité. L’utilisation de l’injection de dépendances n’est pas un scénario courant de la configuration des contrôles d’intégrité. En règle générale, chaque contrôle d’intégrité est assez spécifique au test en question et est configuré à l’aide des méthodes d’extension IHealthChecksBuilder.

L’exemple suivant présente un exemple de contrôle d’intégrité qui récupère un objet de configuration via l’injection de dépendances :

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

Le SampleHealthCheckWithDiConfig et le contrôle d’intégrité doivent être ajoutés au conteneur de service :

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks et MapHealthChecks

Il existe deux façons de rendre les contrôles d’intégrité accessibles aux appelants :

  • UseHealthChecks inscrit l’intergiciel pour gérer les requêtes de contrôle d’intégrité dans le pipeline d’intergiciels.
  • MapHealthChecks inscrit un point de terminaison de contrôle d’intégrité. Le point de terminaison est mis en correspondance et exécuté avec d’autres points de terminaison dans l’application.

Utiliser MapHealthChecks plutôt que UseHealthChecks permet d’utiliser un intergiciel prenant en compte les points de terminaison, comme l’autorisation, et d’avoir un contrôle plus affiné sur la stratégie de correspondance. Utiliser UseHealthChecks plutôt que MapHealthChecks permet principalement de déterminer exactement où les contrôles d’intégrité s’exécutent dans le pipeline d’intergiciel.

UseHealthChecks :

  • Met fin au pipeline quand une requête correspond au point de terminaison de contrôle d’intégrité. Un court-circuit est souvent souhaitable, car il évite le travail inutile, tel que la journalisation et d’autres intergiciels.
  • Sert principalement à configurer l’intergiciel de contrôle d’intégrité dans le pipeline.
  • Peut correspondre à n’importe quel chemin sur un port avec une valeur null ou un élément PathString vide. Autorise l’exécution d’un contrôle d’intégrité sur n’importe quelle requête adressée au port spécifié.
  • Code source

MapHealthChecks autorise :

  • Fin du pipeline quand une requête correspond au point de terminaison de contrôle d’intégrité, en appelant ShortCircuit. Par exemple, app.MapHealthChecks("/healthz").ShortCircuit(); Pour plus d’informations, consultez Court-circuiter l’intergiciel après le routage.
  • Le mappage d’itinéraires ou de points de terminaison spécifiques pour les contrôles d’intégrité.
  • La personnalisation de l’URL ou du chemin où le point de terminaison de contrôle d’intégrité est accessible.
  • Le mappage de plusieurs points de terminaison de contrôle d’intégrité avec différents itinéraires ou configurations. La prise en charge de plusieurs points de terminaison :
    • Active des points de terminaison distincts pour différents types de contrôles d’intégrité ou de composants.
    • Permet d’établir la distinction entre les différents aspects de l’intégrité de l’application ou d’appliquer des configurations spécifiques à des sous-ensembles de contrôles d’intégrité.
  • Code source

Ressources supplémentaires

Remarque

Cet article a été partiellement créé avec l’aide de l’intelligence artificielle. Avant la publication, un auteur a revu et révisé le contenu, si nécessaire. Voir Nos principes d’utilisation du contenu généré par l’IA dans Microsoft Learn.

ASP.NET Core met à disposition un intergiciel de contrôle d’intégrité et des bibliothèques afin de créer des rapports sur l’intégrité des composants d’une infrastructure d’application.

Les contrôles d’intégrité sont exposés par une application comme des points de terminaison HTTP. Les points de terminaison du contrôle d’intégrité peuvent être configurés pour divers scénarios de surveillance en temps réel :

  • Les sondes d’intégrité peuvent être utilisées par les orchestrateurs de conteneurs et les équilibreurs de charge afin de vérifier l’état d’une application. Par exemple, un orchestrateur de conteneurs peut répondre à un résultat de non intégrité en arrêtant le déploiement ou en redémarrant un conteneur. Face à une application non saine, l’équilibreur de charge peut réagir en redirigeant le trafic vers une instance saine.
  • L’utilisation de la mémoire, des disques et des autres ressources de serveur physique peut être supervisée dans le cadre d’un contrôle d’intégrité.
  • Les contrôles d’intégrité peuvent tester les dépendances d’une application, telles que les bases de données et les points de terminaison de service externes, dans le but de vérifier leur disponibilité et leur bon fonctionnement.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

L’exemple d’application comprend des exemples des scénarios décrits dans cet article. Pour exécuter l’exemple d’application selon un scénario donné, utilisez la commande dotnet run dans un interpréteur de commandes, à partir du dossier du projet. Pour plus d’informations sur l’utilisation de l’exemple d’application, consultez le fichier README.md de l’exemple d’application ainsi que les descriptions de scénarios inclus dans cet article.

Prérequis

Les contrôles d’intégrité sont généralement utilisés avec un service de surveillance externe ou un orchestrateur de conteneurs pour vérifier l’état d’une application. Avant d’ajouter des contrôles d’intégrité à une application, vous devez décider du système de supervision à utiliser. Le système de supervision détermine les types de contrôles d’intégrité qui doivent être créés ainsi que la configuration de leurs points de terminaison.

Le package Microsoft.AspNetCore.Diagnostics.HealthChecks est référencé implicitement pour les applications ASP.NET Core. Pour exécuter des contrôles d’intégrité à l’aide d’Entity Framework Core, vous devez ajouter une référence au package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

L’exemple d’application fournit du code de démarrage pour illustrer les contrôles d’intégrité de plusieurs scénarios. Le scénario sonde de base de données vérifie l’intégrité d’une connexion de base de données à l’aide de AspNetCore.Diagnostics.HealthChecks. Le scénario sondage DbContext vérifie une base de données à l’aide d’un EF CoreDbContext. Pour explorer les scénarios de base de données, l’exemple d’application :

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Un autre scénario de contrôle d’intégrité montre comment filtrer des contrôles d’intégrité selon un port de gestion. L’exemple d’application vous oblige à créer un fichier Properties/launchSettings.json comprenant l’URL de gestion et le port de gestion. Pour plus d’informations, consultez la section Filtrer par port.

Sondage d’intégrité de base

Pour de nombreuses applications, un sondage d’intégrité de base qui signale la disponibilité d’une application pour le traitement des requêtes (liveness) suffit à découvrir l’état de l’application.

La configuration de base enregistre les services de contrôle d’intégrité, puis appelle l’intergiciel de contrôle d’intégrité pour répondre à un point de terminaison d’URL avec une réponse sur l’intégrité. Par défaut, aucun contrôle d’intégrité n’est inscrit pour tester les dépendances ou le sous-système. L’application est considérée comme saine si elle est capable de répondre à l’URL de point de terminaison d’intégrité. L’enregistreur de réponse par défaut écrit l’état (HealthStatus) sous forme d’une réponse en texte brut renvoyée au client, qui indique un état HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks dans Startup.Configure.

Dans l’exemple d’application, le point de terminaison du contrôle d’intégrité est créé au niveau de /health (BasicStartup.cs) :

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

Pour exécuter le scénario de configuration de base à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario basic

Exemple Docker

Docker fournit une directive HEALTHCHECK intégrée qui peut être utilisée pour vérifier l’état d’une application utilisant la configuration de contrôle d’intégrité de base :

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

Créer des contrôles d’intégrité

Les contrôles d’intégrité sont créés via l’implémentation de l’interface IHealthCheck. La méthode CheckHealthAsync retourne un HealthCheckResult qui indique l’état d’intégrité comme étant Healthy, Degraded ou Unhealthy. Le résultat est écrit sous la forme de texte en clair avec un code d’état configurable (la configuration est décrite dans la section Options de contrôle d’intégrité). HealthCheckResult peut également retourner des paires clé-valeur facultatives.

La classe ExampleHealthCheck suivante montre la disposition d’un contrôle d’intégrité. La logique du contrôle d’intégrité est placée dans la méthode CheckHealthAsync. L’exemple suivant définit une valeur factice healthCheckResultHealthy à true. Si la valeur de healthCheckResultHealthy est définie sur false, l’état HealthCheckRegistration.FailureStatus est retourné.

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(context.Registration.FailureStatus, 
            "An unhealthy result."));
    }
}

Si CheckHealthAsync lève une exception pendant la vérification, un nouveau HealthReportEntry est retourné avec HealthReportEntry.Status défini sur FailureStatus, qui est défini par AddCheck (voir la section Enregistrer les services de contrôle d’intégrité) et inclut l’exception interne qui a initialement provoqué l’échec de la vérification. Description est défini sur le message de l’exception.

Inscrire les services de contrôle d’intégrité

Le type ExampleHealthCheck est ajouté aux services de contrôle d’intégrité avec AddCheckdans Startup.ConfigureServices :

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

La surcharge AddCheck de l’exemple suivant définit l’état d’échec (HealthStatus) de manière à être signalé lorsque le contrôle d’intégrité signale un échec. Si l’état d’échec est défini sur null (par défaut), HealthStatus.Unhealthy est signalé. Cette surcharge est utile pour les créateurs de bibliothèque, dans les cas où l’état d’échec indiqué par la bibliothèque est appliqué par l’application lorsqu’un échec est signalé par le contrôle d’intégrité, si l’implémentation de ce dernier respecte le paramètre.

Des étiquettes peuvent être utilisées pour filtrer les contrôles d’intégrité (cette procédure est décrite plus loin dans la section Filtrer les contrôles d’intégrité).

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck peut également exécuter une fonction lambda. Dans l’exemple suivant, le nom du contrôle d’intégrité est spécifié en tant que Example, et la vérification retourne toujours un état sain :

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

Appelez AddTypeActivatedCheck pour faire passer des arguments à une implémentation de contrôle d’intégrité. Dans l’exemple suivant, TestHealthCheckWithArgs accepte un entier et une chaîne à utiliser lorsque CheckHealthAsync est appelé :

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs est enregistré en appelant AddTypeActivatedCheck avec l’entier et la chaîne passés à l’implémentation :

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

Utiliser le routage des contrôles d’intégrité

Dans Startup.Configure, appelez MapHealthChecks sur le générateur de points de terminaison avec l’URL du point de terminaison ou le chemin relatif :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

Exiger un hôte

Appelez RequireHost pour spécifier un ou plusieurs hôtes autorisés pour le point de terminaison du contrôle d’intégrité. Les hôtes doivent être de type Unicode plutôt que Punycode, et peuvent inclure un port. Lorsqu’aucune collection n’est fournie, tous les hôtes sont acceptés.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

Pour plus d’informations, consultez la section Filtrer par port.

Exiger une autorisation

Appelez RequireAuthorization pour exécuter l’intergiciel d’autorisation sur le point de terminaison de la requête de contrôle d’intégrité. Une surcharge de RequireAuthorization accepte une ou plusieurs stratégies d’autorisation. Lorsqu’aucune stratégie n’est fournie, la stratégie d’autorisation par défaut est utilisée.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

Activer les requêtes d’origines différentes

Bien qu’il ne soit pas courant d’exécuter des contrôles d’intégrité manuellement à partir d’un navigateur, l’intergiciel CORS peut être activé en appelant RequireCors sur les points de terminaison du contrôle d’intégrité. Une surcharge RequireCors accepte un délégué du générateur de stratégies CORS (CorsPolicyBuilder) ou un nom de stratégie. Lorsqu’aucune stratégie n’est fournie, la stratégie CORS par défaut est utilisée. Pour plus d’informations, consultez Activer les requêtes cross-origin (CORS) dans ASP.NET Core.

Options de contrôle d’intégrité

HealthCheckOptions permet de personnaliser le comportement du contrôle d’intégrité :

Filtrer les contrôles d’intégrité

Par défaut, l’intergiciel de contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui retourne une valeur booléenne à l’option Predicate. Dans l’exemple suivant, le contrôle d’intégrité Bar est filtré en fonction de son étiquette (bar_tag) dans l’instruction conditionnelle de la fonction, où true est retourné uniquement si la propriété Tags du contrôle d’intégrité correspond à foo_tag ou à baz_tag :

Dans Startup.ConfigureServices :

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

Dans Startup.Configure, le Predicate applique un filtre pour exclure le contrôle d’intégrité « Barre ». Seuls Foo et Baz exécutent :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

Personnaliser le code d’état HTTP

Utilisez ResultStatusCodes pour personnaliser le mappage de l’état d’intégrité aux codes d’état HTTP. Les affectations StatusCodes suivantes sont les valeurs par défaut utilisées par le middleware. Vous pouvez modifier les valeurs de code d’état selon vos besoins.

Dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

Supprimer les en-têtes de cache

AllowCachingResponses contrôle si l’intergiciel de contrôle d’intégrité ajoute des en-têtes HTTP à une réponse de sonde pour empêcher la mise en cache de la réponse. Si la valeur est false (par défaut), le middleware définit ou substitue les en-têtes Cache-Control, Expires et Pragma afin d’empêcher la mise en cache de la réponse. Si la valeur est true, le middleware ne modifie pas les en-têtes de cache de la réponse.

Dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

Personnaliser la sortie

Dans Startup.Configure, définissez l’option HealthCheckOptions.ResponseWriter pour un délégué pour écrire la réponse :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

Le délégué par défaut écrit une réponse minimale constituée de texte en clair, avec la valeur de chaîne HealthReport.Status. Les délégués personnalisés suivants génèrent une réponse JSON personnalisée.

Le premier exemple de l’exemple d’application montre la manière d’utiliser System.Text.Json :

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

Le deuxième exemple montre la manière d’utiliser Newtonsoft.Json :

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

Dans l’exemple d’application, mettez la SYSTEM_TEXT_JSON directive de préprocesseur en commentaire dans CustomWriterStartup.cs pour activer la version Newtonsoft.Json de WriteResponse.

L’API de contrôle d’intégrité ne fournit pas de prise en charge intégrée pour les formats de retour JSON complexes, car le format est spécifique à votre choix de système de surveillance. Personnalisez la réponse des exemples précédents selon vos besoins. Pour plus d’informations sur la sérialisation JSON avec System.Text.Json, consultez Comment sérialiser et désérialiser JSON dans .NET.

Sonde de base de données

Un contrôle d’intégrité peut spécifier une requête de base de données à exécuter en tant que test booléen pour indiquer si la base de données répond normalement.

Pour exécuter un contrôle d’intégrité sur une base de données SQL Server, l’exemple d’application utilise AspNetCore.Diagnostics.HealthChecks, un fichier bibliothèque pour le contrôle de l’intégrité des applications ASP.NET Core. AspNetCore.Diagnostics.HealthChecks exécute une demande SELECT 1 sur la base de données pour confirmer que la connexion à la base de données est saine.

Avertissement

Lorsque vous vérifiez une connexion de base de données à l’aide d’une requête, choisissez une requête qui est retournée rapidement. L’utilisation d’une requête risque néanmoins d’entraîner une surcharge de la base de données et d’en diminuer les performances. Dans la plupart des cas, il n’est pas nécessaire d’utiliser une requête de test. Il suffit simplement d’établir une connexion à la base de données. Si vous avez besoin d’exécuter une requête, choisissez une requête SELECT simple, telle que SELECT 1.

Vous devez inclure une référence de package dans AspNetCore.HealthChecks.SqlServer.

Fournissez une chaîne de connexion de base de données valide dans le fichier appsettings.json de l’exemple d’application. L’application utilise une base de données SQL Server nommée HealthCheckSample :

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. L’exemple d’application appelle la méthode AddSqlServer avec la chaîne de connexion de la base de données (DbHealthStartup.cs) :

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Pour exécuter le scénario de sondage d’une base de données à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario db

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Sondage DbContext Entity Framework Core

La vérification DbContext confirme que l’application peut communiquer avec la base de données configurée pour un EF CoreDbContext. La vérification DbContext est prise en charge dans les applications qui :

AddDbContextCheck<TContext> inscrit un contrôle d’intégrité pour un DbContext. Le DbContext est fourni en tant que TContext à la méthode. Une surcharge est disponible pour configurer l’état d’échec, les étiquettes et une requête de test personnalisée.

Par défaut :

  • DbContextHealthCheck appelle la méthode EF Core, CanConnectAsync. Vous pouvez choisir quelle opération doit être exécutée lors du contrôle d’intégrité à l’aide des surcharges de la méthode AddDbContextCheck.
  • Le nom du contrôle d’intégrité correspond à celui du type TContext.

Dans l’exemple d’application, AppDbContext est fourni à AddDbContextCheck, puis est enregistré en tant que service dans Startup.ConfigureServices (DbContextHealthStartup.cs) :

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Pour exécuter le scénario de sondage DbContext à l’aide de l’exemple d’application, vérifiez que la base de données spécifiée par le la chaîne de connexion ne se trouve pas déjà dans l’instance SQL Server. Si la base de données existe, supprimez-la.

Exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario dbcontext

Une fois que l’application est en cours d’exécution, vérifiez l’état d’intégrité en envoyant une requête au point de terminaison /health dans un navigateur. La base de données et AppDbContext n’existent pas, donc l’application fournit la réponse suivante :

Unhealthy

Déclenchez l’exemple d’application pour créer la base de données. Envoyez une requête à /createdatabase. L’application répond :

Creating the database...
Done!
Navigate to /health to see the health status.

Envoyez une requête au point de terminaison /health. La base de données et le contexte existent, donc l’application répond :

Healthy

Déclenchez l’exemple d’application pour supprimer la base de données. Envoyez une requête à /deletedatabase. L’application répond :

Deleting the database...
Done!
Navigate to /health to see the health status.

Envoyez une requête au point de terminaison /health. L’application fournit une réponse non intégrité :

Unhealthy

Séparer les sondages probe readiness et probe liveness

Dans certains scénarios d’hébergement, une paire de contrôles d’intégrité est utilisée pour déterminer deux états de l’application :

  • La disponibilité indique si l’application s’exécute normalement, sans toutefois être prête à recevoir des requêtes.
  • L’activité indique si une application a cessé de fonctionner et doit être redémarrée.

Examinez l’exemple suivant : une application doit télécharger un fichier de configuration volumineux avant d’être prête à traiter les requêtes. Nous ne souhaitons pas que l’application redémarre si le téléchargement initial échoue, car l’application peut réessayer de télécharger le fichier plusieurs fois. Nous utilisons un probe liveness pour décrire l’activité du processus. Aucune autre vérification n’est exécutée. Nous souhaitons également empêcher l’envoi de requêtes à l’application avant la réussite du téléchargement du fichier de configuration. Nous utilisons un probe readiness pour indiquer un état « non prêt », et ce, jusqu’à ce que le téléchargement ait réussi et que l’application soit prête à recevoir des requêtes.

L’exemple d’application contient un contrôle d’intégrité permettant de signaler l’achèvement d’une tâche de démarrage de longue durée dans un service hébergé. StartupHostedServiceHealthCheck expose la propriété StartupTaskCompleted, que le service hébergé peut définir sur true lorsque sa tâche de longue durée est terminée (StartupHostedServiceHealthCheck.cs) :

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

La tâche de longue durée en arrière-plan est démarrée par un service hébergé (Services/StartupHostedService). À la fin de la tâche, StartupHostedServiceHealthCheck.StartupTaskCompleted est défini sur true :

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

Le contrôle d’intégrité est inscrit auprès de AddCheck dans Startup.ConfigureServices en même temps que le service hébergé. Étant donné que le service hébergé doit définir la propriété sur le contrôle d’intégrité, celui-ci est également enregistré dans le conteneur du service (LivenessProbeStartup.cs) :

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure. Dans l’exemple d’application, les points de terminaison du contrôle d’intégrité sont créés au niveau de :

  • /health/ready pour la vérification de la disponibilité. Le test qui permet de vérifier si l’application est prête filtre les contrôles d’intégrité pour n’afficher que celui dont l’étiquette est ready.
  • /health/live pour la vérification de l’activité. La vérification de l’activité applique un filtre pour exclure StartupHostedServiceHealthCheck en retournant false dans HealthCheckOptions.Predicate (pour plus d’informations, consultez Filtrer les contrôles d’intégrité)

Dans l’exemple de code suivant :

  • La vérification de la disponibilité utilise toutes les vérifications enregistrées comportant la balise « ready ».
  • Predicate exclut toutes les vérifications et retourne une valeur 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Pour exécuter le scénario de configuration readiness/liveness à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario liveness

Dans un navigateur, accédez à /health/ready plusieurs fois jusqu’à ce que 15 secondes soient écoulées. Le contrôle d’intégrité signale Unhealthy pendant les 15 premières secondes. Après 15 secondes, le point de terminaison signale Healthy, ce qui reflète l’achèvement de la tâche de longue durée exécutée par le service hébergé.

Cet exemple crée également un éditeur de contrôle d’intégrité (implémentation IHealthCheckPublisher) qui exécute la première vérification de disponibilité avec un délai de deux secondes. Pour plus d’informations, consultez la section Éditeur de vérification de l’intégrité.

Exemple Kubernetes

Dans un environnement tel que Kubernetes, il peut être utile d’utiliser séparément le test permettant de savoir si la l’application est prête et celui visant à savoir si l’application est active. Dans Kubernetes, une application peut devoir exécuter une tâche de démarrage de longue durée avant d’accepter des requêtes, telle qu’un test de la disponibilité de la base de données sous-jacente. L’utilisation séparée des deux tests permet à l’orchestrateur de faire la distinction entre une application qui fonctionne mais qui n’est pas encore prête, et une application qui n’a pas pu démarrer. Pour plus d’informations sur les sondages probe readiness et probe liveness dans Kubernetes, consultez Configure Liveness and Readiness Probes dans la documentation Kubernetes.

L’exemple suivant montre une configuration probe readiness Kubernetes :

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Sonde basée sur les métriques avec un enregistreur de réponse personnalisé

L’exemple d’application montre un contrôle d’intégrité de mémoire avec un enregistreur de réponse personnalisé.

MemoryHealthCheck signale un état détérioré si l’application utilise plus de mémoire que le seuil défini (1 Go dans l’exemple d’application). HealthCheckResult inclut des informations de récupérateur de mémoire pour l’application (MemoryHealthCheck.cs) :

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Au lieu d’activer le contrôle d’intégrité en le passant à AddCheck, MemoryHealthCheck est inscrit en tant que service. Tous les services IHealthCheck inscrits sont disponibles pour les services de contrôle d’intégrité et le middleware. Nous vous recommandons d’inscrire les services de contrôle d’intégrité en tant que services Singleton.

Dans CustomWriterStartup.cs de l’exemple d’application :

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure. Un délégué WriteResponse est fourni à la propriété ResponseWriter pour produire une réponse JSON personnalisée lorsque le contrôle d’intégrité est exécuté :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

Le délégué WriteResponse formate le CompositeHealthCheckResult en un objet JSON et génère une sortie JSON pour la réponse du contrôle d’intégrité. Pour plus d’informations, consultez la section Personnaliser la sortie.

Pour exécuter le sondage basé sur les métriques avec l’enregistreur de réponse personnalisé à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario writer

Remarque

AspNetCore.Diagnostics.HealthChecks inclut des scénarios de contrôle d’intégrité basés sur des métriques, comprenant les vérifications du stockage sur disque et de l’activité selon la valeur maximale.

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Filtrer par port

Appelez RequireHost sur MapHealthChecks à l’aide d’un modèle d’URL qui spécifie un port afin de limiter les requêtes de contrôle d’intégrité au port spécifié. Cette approche est généralement utilisée dans les environnements de conteneur pour exposer un port aux services de surveillance.

L’exemple d’application configure le port à l’aide du fournisseur de configuration des variables d’environnement. Le port est défini dans le fichier launchSettings.json, puis transmis au fournisseur de configuration via une variable d’environnement. Vous devez également configurer le serveur pour écouter les requêtes qui arrivent au port de gestion.

Pour utiliser l’exemple d’application dans le but d’illustrer la configuration du port de gestion, créez le fichier launchSettings.json dans un dossier Properties.

Le fichier Properties/launchSettings.json de l’exemple d’application suivant n’est pas inclus dans les fichiers projet de l’exemple d’application et doit donc être créé manuellement :

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks dans Startup.Configure.

Dans l’exemple d’application, un appel à RequireHost sur le point de terminaison de Startup.Configure spécifie le port de gestion à partir de la configuration :

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

Les points de terminaison sont créés dans l’exemple d’application dans Startup.Configure. Dans l’exemple de code suivant :

  • La vérification de la disponibilité utilise toutes les vérifications enregistrées comportant la balise « ready ».
  • Predicate exclut toutes les vérifications et retourne une valeur 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Remarque

Vous pouvez éviter de créer le fichier launchSettings.json dans l’exemple d’application en définissant le port de gestion explicitement dans le code. Dans Program.csHostBuilder est créé, ajoutez un appel à ListenAnyIP et fournissez le point de terminaison du port de gestion de l’application. Dans Configure de ManagementPortStartup.cs, spécifiez le port de gestion à l’aide de RequireHost :

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

Pour exécuter le scénario de configuration du port de gestion à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario port

Distribuer une bibliothèque de contrôle d’intégrité

Pour distribuer une bibliothèque comme un contrôle d’intégrité :

  1. Écrivez un contrôle d’intégrité qui implémente l’interface IHealthCheck comme une classe autonome. La classe peut utiliser une injection de dépendance, une activation de type et des options nommées pour accéder aux données de configuration.

    Dans la logique des contrôles d’intégrité de CheckHealthAsync :

    • data1 et data2 sont utilisés dans la méthode pour exécuter la logique de contrôle d’intégrité de la sonde.
    • AccessViolationException est géré.

    Lorsqu’une AccessViolationException se produit, FailureStatus est retourné avec HealthCheckResult pour permettre aux utilisateurs de configurer l’état d’échec des contrôles d’intégrité.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. Écrivez une méthode d’extension avec des paramètres que l’application consommatrice appelle dans sa méthode Startup.Configure. Dans l’exemple qui suit, prenons la signature de méthode de contrôle d’intégrité suivante :

    ExampleHealthCheck(string, string, int )
    

    La signature précédente indique que ExampleHealthCheck nécessite des données supplémentaires pour traiter la logique de sondage du contrôle d’intégrité. Les données sont fournies au délégué qui est utilisé pour créer l’instance de contrôle d’intégrité lorsque le contrôle d’intégrité est inscrit avec une méthode d’extension. Dans l’exemple qui suit, l’appelant spécifie les éléments facultatifs suivants :

    • Nom du contrôle d’intégrité (name). Si null, example_health_check est utilisé.
    • Point de données de chaîne du contrôle d’intégrité (data1).
    • Point de données Integer du contrôle d’intégrité (data2). Si null, 1 est utilisé.
    • État d’échec (HealthStatus). Par défaut, il s’agit de null. Si null, HealthStatus.Unhealthy est signalé pour un état d’échec.
    • Étiquettes (IEnumerable<string>).
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

Serveur de publication des contrôles d’intégrité

Quand un IHealthCheckPublisher est ajouté au conteneur du service, le système de contrôle d’intégrité exécute régulièrement vos contrôles d’intégrité et appelle PublishAsync avec le résultat. C’est utile dans un scénario impliquant un système de supervision basé sur les envois (push) et nécessitant que chaque processus appelle le système de supervision régulièrement afin de déterminer l’état d’intégrité.

L’interface IHealthCheckPublisher comprend une seule méthode :

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions vous autorise à définir :

  • Delay : retard initial appliqué après le démarrage de l’application avant d’exécuter les instances IHealthCheckPublisher. Le retard est appliqué à une seule fois au démarrage et ne s’applique pas aux itérations ultérieures. La valeur par défaut est de cinq secondes.
  • Period : période d’exécution de IHealthCheckPublisher. La valeur par défaut est de 30 secondes.
  • Predicate : si Predicate est null (valeur par défaut), le service de publication du contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui filtre l’ensemble de vérifications. Le prédicat est évalué à chaque période.
  • Timeout : délai d’attente pour l’exécution des contrôles d’intégrité pour toutes les instances IHealthCheckPublisher. Utilisez InfiniteTimeSpan pour une exécution sans délai d’attente. La valeur par défaut est de 30 secondes.

Dans l’exemple d’application, ReadinessPublisher est une implémentation IHealthCheckPublisher. L’état du contrôle d’intégrité est journalisé pour chaque contrôle au niveau du journal :

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

Dans l’exemple d’application LivenessProbeStartup, la vérification de la disponibilité StartupHostedService a un délai de démarrage de deux secondes et exécute la vérification toutes les 30 secondes. Pour activer l’implémentation IHealthCheckPublisher, l’exemple enregistre ReadinessPublisher comme un service singleton dans le conteneur d’injection de dépendance (DI) :

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Remarque

AspNetCore.Diagnostics.HealthChecks inclut des éditeurs de plusieurs systèmes, y compris Application Insights.

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Restreindre les vérifications d’intégrité avec MapWhen

Utilisez MapWhen pour créer une branche conditionnelle du pipeline des demandes pour les points de terminaison de contrôle d’intégrité.

Dans l’exemple suivant, MapWhen crée une branche du pipeline des requêtes pour activer l’intergiciel de contrôle d’intégrité si une requête GET est reçue pour le point de terminaison api/HealthCheck :

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Pour plus d’informations, consultez Intergiciel (middleware) ASP.NET Core.

ASP.NET Core met à disposition un intergiciel de contrôle d’intégrité et des bibliothèques afin de créer des rapports sur l’intégrité des composants d’une infrastructure d’application.

Les contrôles d’intégrité sont exposés par une application comme des points de terminaison HTTP. Les points de terminaison du contrôle d’intégrité peuvent être configurés pour divers scénarios de surveillance en temps réel :

  • Les sondes d’intégrité peuvent être utilisées par les orchestrateurs de conteneurs et les équilibreurs de charge afin de vérifier l’état d’une application. Par exemple, un orchestrateur de conteneurs peut répondre à un résultat de non intégrité en arrêtant le déploiement ou en redémarrant un conteneur. Face à une application non saine, l’équilibreur de charge peut réagir en redirigeant le trafic vers une instance saine.
  • L’utilisation de la mémoire, des disques et des autres ressources de serveur physique peut être supervisée dans le cadre d’un contrôle d’intégrité.
  • Les contrôles d’intégrité peuvent tester les dépendances d’une application, telles que les bases de données et les points de terminaison de service externes, dans le but de vérifier leur disponibilité et leur bon fonctionnement.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

L’exemple d’application comprend des exemples des scénarios décrits dans cet article. Pour exécuter l’exemple d’application selon un scénario donné, utilisez la commande dotnet run dans un interpréteur de commandes, à partir du dossier du projet. Pour plus d’informations sur l’utilisation de l’exemple d’application, consultez le fichier README.md de l’exemple d’application ainsi que les descriptions de scénarios inclus dans cet article.

Prérequis

Les contrôles d’intégrité sont généralement utilisés avec un service de surveillance externe ou un orchestrateur de conteneurs pour vérifier l’état d’une application. Avant d’ajouter des contrôles d’intégrité à une application, vous devez décider du système de supervision à utiliser. Le système de supervision détermine les types de contrôles d’intégrité qui doivent être créés ainsi que la configuration de leurs points de terminaison.

Le package Microsoft.AspNetCore.Diagnostics.HealthChecks est référencé implicitement pour les applications ASP.NET Core. Pour exécuter des contrôles d’intégrité à l’aide d’Entity Framework Core, vous devez ajouter un package de référence au package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

L’exemple d’application fournit du code de démarrage pour illustrer les contrôles d’intégrité de plusieurs scénarios. Le scénario sonde de base de données vérifie l’intégrité d’une connexion de base de données à l’aide de AspNetCore.Diagnostics.HealthChecks. Le scénario sondage DbContext vérifie une base de données à l’aide d’un EF CoreDbContext. Pour explorer les scénarios de base de données, l’exemple d’application :

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Un autre scénario de contrôle d’intégrité montre comment filtrer des contrôles d’intégrité selon un port de gestion. L’exemple d’application vous oblige à créer un fichier Properties/launchSettings.json comprenant l’URL de gestion et le port de gestion. Pour plus d’informations, consultez la section Filtrer par port.

Sondage d’intégrité de base

Pour de nombreuses applications, un sondage d’intégrité de base qui signale la disponibilité d’une application pour le traitement des requêtes (liveness) suffit à découvrir l’état de l’application.

La configuration de base enregistre les services de contrôle d’intégrité, puis appelle l’intergiciel de contrôle d’intégrité pour répondre à un point de terminaison d’URL avec une réponse sur l’intégrité. Par défaut, aucun contrôle d’intégrité n’est inscrit pour tester les dépendances ou le sous-système. L’application est considérée comme saine si elle est capable de répondre à l’URL de point de terminaison d’intégrité. L’enregistreur de réponse par défaut écrit l’état (HealthStatus) sous forme d’une réponse en texte brut renvoyée au client, qui indique un état HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks dans Startup.Configure.

Dans l’exemple d’application, le point de terminaison du contrôle d’intégrité est créé au niveau de /health (BasicStartup.cs) :

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

Pour exécuter le scénario de configuration de base à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario basic

Exemple Docker

Docker fournit une directive HEALTHCHECK intégrée qui peut être utilisée pour vérifier l’état d’une application utilisant la configuration de contrôle d’intégrité de base :

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

Créer des contrôles d’intégrité

Les contrôles d’intégrité sont créés via l’implémentation de l’interface IHealthCheck. La méthode CheckHealthAsync retourne un HealthCheckResult qui indique l’état d’intégrité comme étant Healthy, Degraded ou Unhealthy. Le résultat est écrit sous la forme de texte en clair avec un code d’état configurable (la configuration est décrite dans la section Options de contrôle d’intégrité). HealthCheckResult peut également retourner des paires clé-valeur facultatives.

La classe ExampleHealthCheck suivante montre la disposition d’un contrôle d’intégrité. La logique du contrôle d’intégrité est placée dans la méthode CheckHealthAsync. L’exemple suivant définit une valeur factice healthCheckResultHealthy à true. Si la valeur de healthCheckResultHealthy est définie sur false, l’état HealthCheckResult.Unhealthy est retourné.

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("An unhealthy result."));
    }
}

Inscrire les services de contrôle d’intégrité

Le type ExampleHealthCheck est ajouté aux services de contrôle d’intégrité avec AddCheckdans Startup.ConfigureServices :

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

La surcharge AddCheck de l’exemple suivant définit l’état d’échec (HealthStatus) de manière à être signalé lorsque le contrôle d’intégrité signale un échec. Si l’état d’échec est défini sur null (par défaut), HealthStatus.Unhealthy est signalé. Cette surcharge est utile pour les créateurs de bibliothèque, dans les cas où l’état d’échec indiqué par la bibliothèque est appliqué par l’application lorsqu’un échec est signalé par le contrôle d’intégrité, si l’implémentation de ce dernier respecte le paramètre.

Des étiquettes peuvent être utilisées pour filtrer les contrôles d’intégrité (cette procédure est décrite plus loin dans la section Filtrer les contrôles d’intégrité).

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck peut également exécuter une fonction lambda. Dans l’exemple suivant, le nom du contrôle d’intégrité est spécifié en tant que Example, et la vérification retourne toujours un état sain :

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

Appelez AddTypeActivatedCheck pour faire passer des arguments à une implémentation de contrôle d’intégrité. Dans l’exemple suivant, TestHealthCheckWithArgs accepte un entier et une chaîne à utiliser lorsque CheckHealthAsync est appelé :

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs est enregistré en appelant AddTypeActivatedCheck avec l’entier et la chaîne passés à l’implémentation :

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

Utiliser le routage des contrôles d’intégrité

Dans Startup.Configure, appelez MapHealthChecks sur le générateur de points de terminaison avec l’URL du point de terminaison ou le chemin relatif :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

Exiger un hôte

Appelez RequireHost pour spécifier un ou plusieurs hôtes autorisés pour le point de terminaison du contrôle d’intégrité. Les hôtes doivent être de type Unicode plutôt que Punycode, et peuvent inclure un port. Lorsqu’aucune collection n’est fournie, tous les hôtes sont acceptés.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

Pour plus d’informations, consultez la section Filtrer par port.

Exiger une autorisation

Appelez RequireAuthorization pour exécuter l’intergiciel d’autorisation sur le point de terminaison de la requête de contrôle d’intégrité. Une surcharge de RequireAuthorization accepte une ou plusieurs stratégies d’autorisation. Lorsqu’aucune stratégie n’est fournie, la stratégie d’autorisation par défaut est utilisée.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

Activer les requêtes d’origines différentes

Bien qu’il ne soit pas courant d’exécuter des contrôles d’intégrité manuellement à partir d’un navigateur, l’intergiciel CORS peut être activé en appelant RequireCors sur les points de terminaison du contrôle d’intégrité. Une surcharge RequireCors accepte un délégué du générateur de stratégies CORS (CorsPolicyBuilder) ou un nom de stratégie. Lorsqu’aucune stratégie n’est fournie, la stratégie CORS par défaut est utilisée. Pour plus d’informations, consultez Activer les requêtes cross-origin (CORS) dans ASP.NET Core.

Options de contrôle d’intégrité

HealthCheckOptions permet de personnaliser le comportement du contrôle d’intégrité :

Filtrer les contrôles d’intégrité

Par défaut, l’intergiciel de contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui retourne une valeur booléenne à l’option Predicate. Dans l’exemple suivant, le contrôle d’intégrité Bar est filtré en fonction de son étiquette (bar_tag) dans l’instruction conditionnelle de la fonction, où true est retourné uniquement si la propriété Tags du contrôle d’intégrité correspond à foo_tag ou à baz_tag :

Dans Startup.ConfigureServices :

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

Dans Startup.Configure, le Predicate applique un filtre pour exclure le contrôle d’intégrité « Barre ». Seuls Foo et Baz exécutent :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

Personnaliser le code d’état HTTP

Utilisez ResultStatusCodes pour personnaliser le mappage de l’état d’intégrité aux codes d’état HTTP. Les affectations StatusCodes suivantes sont les valeurs par défaut utilisées par le middleware. Vous pouvez modifier les valeurs de code d’état selon vos besoins.

Dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

Supprimer les en-têtes de cache

AllowCachingResponses contrôle si l’intergiciel de contrôle d’intégrité ajoute des en-têtes HTTP à une réponse de sonde pour empêcher la mise en cache de la réponse. Si la valeur est false (par défaut), le middleware définit ou substitue les en-têtes Cache-Control, Expires et Pragma afin d’empêcher la mise en cache de la réponse. Si la valeur est true, le middleware ne modifie pas les en-têtes de cache de la réponse.

Dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

Personnaliser la sortie

Dans Startup.Configure, définissez l’option HealthCheckOptions.ResponseWriter pour un délégué pour écrire la réponse :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

Le délégué par défaut écrit une réponse minimale constituée de texte en clair, avec la valeur de chaîne HealthReport.Status. Les délégués personnalisés suivants génèrent une réponse JSON personnalisée.

Le premier exemple de l’exemple d’application montre la manière d’utiliser System.Text.Json :

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

Le deuxième exemple montre la manière d’utiliser Newtonsoft.Json :

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

Dans l’exemple d’application, mettez la SYSTEM_TEXT_JSON directive de préprocesseur en commentaire dans CustomWriterStartup.cs pour activer la version Newtonsoft.Json de WriteResponse.

L’API de contrôle d’intégrité ne fournit pas de prise en charge intégrée pour les formats de retour JSON complexes, car le format est spécifique à votre choix de système de surveillance. Personnalisez la réponse des exemples précédents selon vos besoins. Pour plus d’informations sur la sérialisation JSON avec System.Text.Json, consultez Comment sérialiser et désérialiser JSON dans .NET.

Sonde de base de données

Un contrôle d’intégrité peut spécifier une requête de base de données à exécuter en tant que test booléen pour indiquer si la base de données répond normalement.

Pour exécuter un contrôle d’intégrité sur une base de données SQL Server, l’exemple d’application utilise AspNetCore.Diagnostics.HealthChecks, un fichier bibliothèque pour le contrôle de l’intégrité des applications ASP.NET Core. AspNetCore.Diagnostics.HealthChecks exécute une demande SELECT 1 sur la base de données pour confirmer que la connexion à la base de données est saine.

Avertissement

Lorsque vous vérifiez une connexion de base de données à l’aide d’une requête, choisissez une requête qui est retournée rapidement. L’utilisation d’une requête risque néanmoins d’entraîner une surcharge de la base de données et d’en diminuer les performances. Dans la plupart des cas, il n’est pas nécessaire d’utiliser une requête de test. Il suffit simplement d’établir une connexion à la base de données. Si vous avez besoin d’exécuter une requête, choisissez une requête SELECT simple, telle que SELECT 1.

Vous devez inclure une référence de package dans AspNetCore.HealthChecks.SqlServer.

Fournissez une chaîne de connexion de base de données valide dans le fichier appsettings.json de l’exemple d’application. L’application utilise une base de données SQL Server nommée HealthCheckSample :

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. L’exemple d’application appelle la méthode AddSqlServer avec la chaîne de connexion de la base de données (DbHealthStartup.cs) :

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Pour exécuter le scénario de sondage d’une base de données à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario db

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Sondage DbContext Entity Framework Core

La vérification DbContext confirme que l’application peut communiquer avec la base de données configurée pour un EF CoreDbContext. La vérification DbContext est prise en charge dans les applications qui :

AddDbContextCheck<TContext> inscrit un contrôle d’intégrité pour un DbContext. Le DbContext est fourni en tant que TContext à la méthode. Une surcharge est disponible pour configurer l’état d’échec, les étiquettes et une requête de test personnalisée.

Par défaut :

  • DbContextHealthCheck appelle la méthode EF Core, CanConnectAsync. Vous pouvez choisir quelle opération doit être exécutée lors du contrôle d’intégrité à l’aide des surcharges de la méthode AddDbContextCheck.
  • Le nom du contrôle d’intégrité correspond à celui du type TContext.

Dans l’exemple d’application, AppDbContext est fourni à AddDbContextCheck, puis est enregistré en tant que service dans Startup.ConfigureServices (DbContextHealthStartup.cs) :

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Pour exécuter le scénario de sondage DbContext à l’aide de l’exemple d’application, vérifiez que la base de données spécifiée par le la chaîne de connexion ne se trouve pas déjà dans l’instance SQL Server. Si la base de données existe, supprimez-la.

Exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario dbcontext

Une fois que l’application est en cours d’exécution, vérifiez l’état d’intégrité en envoyant une requête au point de terminaison /health dans un navigateur. La base de données et AppDbContext n’existent pas, donc l’application fournit la réponse suivante :

Unhealthy

Déclenchez l’exemple d’application pour créer la base de données. Envoyez une requête à /createdatabase. L’application répond :

Creating the database...
Done!
Navigate to /health to see the health status.

Envoyez une requête au point de terminaison /health. La base de données et le contexte existent, donc l’application répond :

Healthy

Déclenchez l’exemple d’application pour supprimer la base de données. Envoyez une requête à /deletedatabase. L’application répond :

Deleting the database...
Done!
Navigate to /health to see the health status.

Envoyez une requête au point de terminaison /health. L’application fournit une réponse non intégrité :

Unhealthy

Séparer les sondages probe readiness et probe liveness

Dans certains scénarios d’hébergement, une paire de contrôles d’intégrité est utilisée pour déterminer deux états de l’application :

  • La disponibilité indique si l’application s’exécute normalement, sans toutefois être prête à recevoir des requêtes.
  • L’activité indique si une application a cessé de fonctionner et doit être redémarrée.

Examinez l’exemple suivant : une application doit télécharger un fichier de configuration volumineux avant d’être prête à traiter les requêtes. Nous ne souhaitons pas que l’application redémarre si le téléchargement initial échoue, car l’application peut réessayer de télécharger le fichier plusieurs fois. Nous utilisons un probe liveness pour décrire l’activité du processus. Aucune autre vérification n’est exécutée. Nous souhaitons également empêcher l’envoi de requêtes à l’application avant la réussite du téléchargement du fichier de configuration. Nous utilisons un probe readiness pour indiquer un état « non prêt », et ce, jusqu’à ce que le téléchargement ait réussi et que l’application soit prête à recevoir des requêtes.

L’exemple d’application contient un contrôle d’intégrité permettant de signaler l’achèvement d’une tâche de démarrage de longue durée dans un service hébergé. StartupHostedServiceHealthCheck expose la propriété StartupTaskCompleted, que le service hébergé peut définir sur true lorsque sa tâche de longue durée est terminée (StartupHostedServiceHealthCheck.cs) :

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

La tâche de longue durée en arrière-plan est démarrée par un service hébergé (Services/StartupHostedService). À la fin de la tâche, StartupHostedServiceHealthCheck.StartupTaskCompleted est défini sur true :

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

Le contrôle d’intégrité est inscrit auprès de AddCheck dans Startup.ConfigureServices en même temps que le service hébergé. Étant donné que le service hébergé doit définir la propriété sur le contrôle d’intégrité, celui-ci est également enregistré dans le conteneur du service (LivenessProbeStartup.cs) :

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure. Dans l’exemple d’application, les points de terminaison du contrôle d’intégrité sont créés au niveau de :

  • /health/ready pour la vérification de la disponibilité. Le test qui permet de vérifier si l’application est prête filtre les contrôles d’intégrité pour n’afficher que celui dont l’étiquette est ready.
  • /health/live pour la vérification de l’activité. La vérification de l’activité applique un filtre pour exclure StartupHostedServiceHealthCheck en retournant false dans HealthCheckOptions.Predicate (pour plus d’informations, consultez Filtrer les contrôles d’intégrité)

Dans l’exemple de code suivant :

  • La vérification de la disponibilité utilise toutes les vérifications enregistrées comportant la balise « ready ».
  • Predicate exclut toutes les vérifications et retourne une valeur 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Pour exécuter le scénario de configuration readiness/liveness à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario liveness

Dans un navigateur, accédez à /health/ready plusieurs fois jusqu’à ce que 15 secondes soient écoulées. Le contrôle d’intégrité signale Unhealthy pendant les 15 premières secondes. Après 15 secondes, le point de terminaison signale Healthy, ce qui reflète l’achèvement de la tâche de longue durée exécutée par le service hébergé.

Cet exemple crée également un éditeur de contrôle d’intégrité (implémentation IHealthCheckPublisher) qui exécute la première vérification de disponibilité avec un délai de deux secondes. Pour plus d’informations, consultez la section Éditeur de vérification de l’intégrité.

Exemple Kubernetes

Dans un environnement tel que Kubernetes, il peut être utile d’utiliser séparément le test permettant de savoir si la l’application est prête et celui visant à savoir si l’application est active. Dans Kubernetes, une application peut devoir exécuter une tâche de démarrage de longue durée avant d’accepter des requêtes, telle qu’un test de la disponibilité de la base de données sous-jacente. L’utilisation séparée des deux tests permet à l’orchestrateur de faire la distinction entre une application qui fonctionne mais qui n’est pas encore prête, et une application qui n’a pas pu démarrer. Pour plus d’informations sur les sondages probe readiness et probe liveness dans Kubernetes, consultez Configure Liveness and Readiness Probes dans la documentation Kubernetes.

L’exemple suivant montre une configuration probe readiness Kubernetes :

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Sonde basée sur les métriques avec un enregistreur de réponse personnalisé

L’exemple d’application montre un contrôle d’intégrité de mémoire avec un enregistreur de réponse personnalisé.

MemoryHealthCheck signale un état détérioré si l’application utilise plus de mémoire que le seuil défini (1 Go dans l’exemple d’application). HealthCheckResult inclut des informations de récupérateur de mémoire pour l’application (MemoryHealthCheck.cs) :

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Au lieu d’activer le contrôle d’intégrité en le passant à AddCheck, MemoryHealthCheck est inscrit en tant que service. Tous les services IHealthCheck inscrits sont disponibles pour les services de contrôle d’intégrité et le middleware. Nous vous recommandons d’inscrire les services de contrôle d’intégrité en tant que services Singleton.

Dans CustomWriterStartup.cs de l’exemple d’application :

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

Un point de terminaison de contrôle d’intégrité est créé en appelant MapHealthChecks dans Startup.Configure. Un délégué WriteResponse est fourni à la propriété ResponseWriter pour produire une réponse JSON personnalisée lorsque le contrôle d’intégrité est exécuté :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

Le délégué WriteResponse formate le CompositeHealthCheckResult en un objet JSON et génère une sortie JSON pour la réponse du contrôle d’intégrité. Pour plus d’informations, consultez la section Personnaliser la sortie.

Pour exécuter le sondage basé sur les métriques avec l’enregistreur de réponse personnalisé à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario writer

Remarque

AspNetCore.Diagnostics.HealthChecks inclut des scénarios de contrôle d’intégrité basés sur des métriques, comprenant les vérifications du stockage sur disque et de l’activité selon la valeur maximale.

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Filtrer par port

Appelez RequireHost sur MapHealthChecks à l’aide d’un modèle d’URL qui spécifie un port afin de limiter les requêtes de contrôle d’intégrité au port spécifié. Cette approche est généralement utilisée dans les environnements de conteneur pour exposer un port aux services de surveillance.

L’exemple d’application configure le port à l’aide du fournisseur de configuration des variables d’environnement. Le port est défini dans le fichier launchSettings.json, puis transmis au fournisseur de configuration via une variable d’environnement. Vous devez également configurer le serveur pour écouter les requêtes qui arrivent au port de gestion.

Pour utiliser l’exemple d’application dans le but d’illustrer la configuration du port de gestion, créez le fichier launchSettings.json dans un dossier Properties.

Le fichier Properties/launchSettings.json de l’exemple d’application suivant n’est pas inclus dans les fichiers projet de l’exemple d’application et doit donc être créé manuellement :

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Startup.ConfigureServices. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks dans Startup.Configure.

Dans l’exemple d’application, un appel à RequireHost sur le point de terminaison de Startup.Configure spécifie le port de gestion à partir de la configuration :

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

Les points de terminaison sont créés dans l’exemple d’application dans Startup.Configure. Dans l’exemple de code suivant :

  • La vérification de la disponibilité utilise toutes les vérifications enregistrées comportant la balise « ready ».
  • Predicate exclut toutes les vérifications et retourne une valeur 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Remarque

Vous pouvez éviter de créer le fichier launchSettings.json dans l’exemple d’application en définissant le port de gestion explicitement dans le code. Dans Program.csHostBuilder est créé, ajoutez un appel à ListenAnyIP et fournissez le point de terminaison du port de gestion de l’application. Dans Configure de ManagementPortStartup.cs, spécifiez le port de gestion à l’aide de RequireHost :

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs :

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

Pour exécuter le scénario de configuration du port de gestion à l’aide de l’exemple d’application, exécutez la commande suivante à partir du dossier du projet, dans un interpréteur de commandes :

dotnet run --scenario port

Distribuer une bibliothèque de contrôle d’intégrité

Pour distribuer une bibliothèque comme un contrôle d’intégrité :

  1. Écrivez un contrôle d’intégrité qui implémente l’interface IHealthCheck comme une classe autonome. La classe peut utiliser une injection de dépendance, une activation de type et des options nommées pour accéder aux données de configuration.

    Dans la logique des contrôles d’intégrité de CheckHealthAsync :

    • data1 et data2 sont utilisés dans la méthode pour exécuter la logique de contrôle d’intégrité de la sonde.
    • AccessViolationException est géré.

    Lorsqu’une AccessViolationException se produit, FailureStatus est retourné avec HealthCheckResult pour permettre aux utilisateurs de configurer l’état d’échec des contrôles d’intégrité.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. Écrivez une méthode d’extension avec des paramètres que l’application consommatrice appelle dans sa méthode Startup.Configure. Dans l’exemple qui suit, prenons la signature de méthode de contrôle d’intégrité suivante :

    ExampleHealthCheck(string, string, int )
    

    La signature précédente indique que ExampleHealthCheck nécessite des données supplémentaires pour traiter la logique de sondage du contrôle d’intégrité. Les données sont fournies au délégué qui est utilisé pour créer l’instance de contrôle d’intégrité lorsque le contrôle d’intégrité est inscrit avec une méthode d’extension. Dans l’exemple qui suit, l’appelant spécifie les éléments facultatifs suivants :

    • Nom du contrôle d’intégrité (name). Si null, example_health_check est utilisé.
    • Point de données de chaîne du contrôle d’intégrité (data1).
    • Point de données Integer du contrôle d’intégrité (data2). Si null, 1 est utilisé.
    • État d’échec (HealthStatus). Par défaut, il s’agit de null. Si null, HealthStatus.Unhealthy est signalé pour un état d’échec.
    • Étiquettes (IEnumerable<string>).
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

Serveur de publication des contrôles d’intégrité

Quand un IHealthCheckPublisher est ajouté au conteneur du service, le système de contrôle d’intégrité exécute régulièrement vos contrôles d’intégrité et appelle PublishAsync avec le résultat. C’est utile dans un scénario impliquant un système de supervision basé sur les envois (push) et nécessitant que chaque processus appelle le système de supervision régulièrement afin de déterminer l’état d’intégrité.

L’interface IHealthCheckPublisher comprend une seule méthode :

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions vous autorise à définir :

  • Delay : retard initial appliqué après le démarrage de l’application avant d’exécuter les instances IHealthCheckPublisher. Le retard est appliqué à une seule fois au démarrage et ne s’applique pas aux itérations ultérieures. La valeur par défaut est de cinq secondes.
  • Period : période d’exécution de IHealthCheckPublisher. La valeur par défaut est de 30 secondes.
  • Predicate : si Predicate est null (valeur par défaut), le service de publication du contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui filtre l’ensemble de vérifications. Le prédicat est évalué à chaque période.
  • Timeout : délai d’attente pour l’exécution des contrôles d’intégrité pour toutes les instances IHealthCheckPublisher. Utilisez InfiniteTimeSpan pour une exécution sans délai d’attente. La valeur par défaut est de 30 secondes.

Dans l’exemple d’application, ReadinessPublisher est une implémentation IHealthCheckPublisher. L’état du contrôle d’intégrité est journalisé pour chaque contrôle au niveau du journal :

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

Dans l’exemple d’application LivenessProbeStartup, la vérification de la disponibilité StartupHostedService a un délai de démarrage de deux secondes et exécute la vérification toutes les 30 secondes. Pour activer l’implémentation IHealthCheckPublisher, l’exemple enregistre ReadinessPublisher comme un service singleton dans le conteneur d’injection de dépendance (DI) :

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Remarque

AspNetCore.Diagnostics.HealthChecks inclut des éditeurs de plusieurs systèmes, y compris Application Insights.

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Restreindre les vérifications d’intégrité avec MapWhen

Utilisez MapWhen pour créer une branche conditionnelle du pipeline des demandes pour les points de terminaison de contrôle d’intégrité.

Dans l’exemple suivant, MapWhen crée une branche du pipeline des requêtes pour activer l’intergiciel de contrôle d’intégrité si une requête GET est reçue pour le point de terminaison api/HealthCheck :

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Pour plus d’informations, consultez Intergiciel (middleware) ASP.NET Core.

ASP.NET Core met à disposition un intergiciel de contrôle d’intégrité et des bibliothèques afin de créer des rapports sur l’intégrité des composants d’une infrastructure d’application.

Les contrôles d’intégrité sont exposés par une application comme des points de terminaison HTTP. Les points de terminaison du contrôle d’intégrité peuvent être configurés pour divers scénarios de surveillance en temps réel :

  • Les sondes d’intégrité peuvent être utilisées par les orchestrateurs de conteneurs et les équilibreurs de charge afin de vérifier l’état d’une application. Par exemple, un orchestrateur de conteneurs peut répondre à un résultat de non intégrité en arrêtant le déploiement ou en redémarrant un conteneur. Face à une application non saine, l’équilibreur de charge peut réagir en redirigeant le trafic vers une instance saine.
  • L’utilisation de la mémoire, des disques et des autres ressources de serveur physique peut être supervisée dans le cadre d’un contrôle d’intégrité.
  • Les contrôles d’intégrité peuvent tester les dépendances d’une application, telles que les bases de données et les points de terminaison de service externes, dans le but de vérifier leur disponibilité et leur bon fonctionnement.

Les contrôles d’intégrité sont généralement utilisés avec un service de surveillance externe ou un orchestrateur de conteneurs pour vérifier l’état d’une application. Avant d’ajouter des contrôles d’intégrité à une application, vous devez décider du système de supervision à utiliser. Le système de supervision détermine les types de contrôles d’intégrité qui doivent être créés ainsi que la configuration de leurs points de terminaison.

Sondage d’intégrité de base

Pour de nombreuses applications, un sondage d’intégrité de base qui signale la disponibilité d’une application pour le traitement des requêtes (liveness) suffit à découvrir l’état de l’application.

La configuration de base enregistre les services de contrôle d’intégrité, puis appelle l’intergiciel de contrôle d’intégrité pour répondre à un point de terminaison d’URL avec une réponse sur l’intégrité. Par défaut, aucun contrôle d’intégrité n’est inscrit pour tester les dépendances ou le sous-système. L’application est considérée comme saine si elle est capable de répondre à l’URL de point de terminaison d’intégrité. L’enregistreur de réponses par défaut écrit HealthStatus comme réponse en texte brut au client. Le HealthStatus est HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Pour inscrire les services de contrôle d’intégrité, utilisez AddHealthChecks dans Program.cs. Créez un point de terminaison de contrôle d’intégrité en appelant MapHealthChecks.

L’exemple suivant crée un point de terminaison de contrôle d’intégrité sur /healthz :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker fournit une directive HEALTHCHECK intégrée qui peut être utilisée pour vérifier l’état d’une application utilisant la configuration de contrôle d’intégrité de base :

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

L’exemple précédent utilise curl pour envoyer une requête HTTP au point de terminaison de contrôle d’intégrité à /healthz. curl n’est pas inclus dans les images conteneur Linux .NET, mais il peut être ajouté par l’installation le package requis dans le Dockerfile. Les conteneurs qui utilisent des images basées sur Alpine Linux peuvent utiliser le wget inclus à la place de curl.

Créer des contrôles d’intégrité

Les contrôles d’intégrité sont créés via l’implémentation de l’interface IHealthCheck. La méthode CheckHealthAsync retourne un HealthCheckResult qui indique l’état d’intégrité comme étant Healthy, Degraded ou Unhealthy. Le résultat est écrit sous forme de réponse en texte brut avec un code d’état configurable. La configuration est décrite dans la section Options de contrôle d’intégrité. HealthCheckResult peut également retourner des paires clé-valeur facultatives.

L’exemple suivant montre la disposition d’un contrôle d’intégrité :

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

La logique du contrôle d’intégrité est placée dans la méthode CheckHealthAsync. L’exemple précédent définit une variable factice, de isHealthy, à true. Si la valeur de isHealthy est définie sur false, l’état HealthCheckRegistration.FailureStatus est retourné.

Si CheckHealthAsync lève une exception durant la vérification, un nouvel état HealthReportEntry est retourné avec son HealthReportEntry.Status défini sur FailureStatus. Cet état est défini par AddCheck (consulter la section Enregistrer les services de contrôle d’intégrité) et inclut l’exception interne qui a provoqué l’échec de la vérification. Description est défini sur le message de l’exception.

Inscrire les services de contrôle d’intégrité

Pour enregistrer un service de contrôle d’intégrité, appelez AddCheck dans Program.cs :

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

La surcharge AddCheck de l’exemple suivant définit l’état d’échec (HealthStatus) de manière à être signalé lorsque le contrôle d’intégrité signale un échec. Si l’état d’échec est défini sur null (par défaut), HealthStatus.Unhealthy est signalé. Cette surcharge est utile pour les créateurs de bibliothèque, dans les cas où l’état d’échec indiqué par la bibliothèque est appliqué par l’application lorsqu’un échec est signalé par le contrôle d’intégrité, si l’implémentation de ce dernier respecte le paramètre.

Les contrôles d’intégrité peuvent être filtrés à l’aide de balises. Les balises sont décrites dans la section Filtrer les contrôles d’intégrité.

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck peut également exécuter une fonction lambda. Dans l’exemple suivant, le contrôle d’intégrité retourne toujours un résultat sain :

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

Appelez AddTypeActivatedCheck pour faire passer des arguments à une implémentation de contrôle d’intégrité. Dans l’exemple suivant, un contrôle d’intégrité activé par type accepte un entier et une chaîne dans son constructeur :

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

Pour enregistrer le contrôle d’intégrité précédent, appelez AddTypeActivatedCheck avec l’entier et la chaîne passés en tant qu’arguments :

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

Utiliser le routage des contrôles d’intégrité

Dans Program.cs, appelez MapHealthChecks sur le générateur de points de terminaison avec l’URL du point de terminaison ou le chemin relatif :

app.MapHealthChecks("/healthz");

Exiger un hôte

Appelez RequireHost pour spécifier un ou plusieurs hôtes autorisés pour le point de terminaison du contrôle d’intégrité. Les hôtes doivent être de type Unicode plutôt que Punycode, et peuvent inclure un port. Lorsqu’aucune collection n’est fournie, tous les hôtes sont acceptés :

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

Pour limiter la réponse du point de terminaison du contrôle d’intégrité à un port spécifique uniquement, spécifiez un port dans l’appel à RequireHost. Cette approche est généralement utilisée dans les environnements de conteneur pour exposer un port aux services de surveillance :

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

Avertissement

L’API qui s’appuie sur l’en-tête d’hôte, comme HttpRequest.Host et RequireHost, est soumise à une usurpation potentielle par les clients.

Pour éviter l’usurpation d’hôte ou de port, utilisez l’une des approches suivantes :

Pour empêcher les clients non autorisés d’usurper le port, appelez RequireAuthorization :

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

Pour plus d’informations, consultez Correspondance de l’hôte dans les itinéraires avec RequireHost.

Exiger une autorisation

Appelez RequireAuthorization pour exécuter l’intergiciel d’autorisation sur le point de terminaison de la requête de contrôle d’intégrité. Une surcharge de RequireAuthorization accepte une ou plusieurs stratégies d’autorisation. Lorsqu’aucune stratégie n’est fournie, la stratégie d’autorisation par défaut est utilisée :

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

Activer les requêtes d’origines différentes

Bien qu’il ne soit pas courant d’exécuter les contrôles d’intégrité manuellement à partir d’un navigateur, l’intergiciel CORS peut être activé en appelant RequireCors sur les points de terminaison du contrôle d’intégrité. La surcharge RequireCors accepte un délégué du générateur de stratégies CORS (CorsPolicyBuilder) ou un nom de stratégie. Pour plus d’informations, consultez Activer les requêtes cross-origin (CORS) dans ASP.NET Core.

Options de contrôle d’intégrité

HealthCheckOptions permet de personnaliser le comportement du contrôle d’intégrité :

Filtrer les contrôles d’intégrité

Par défaut, l’intergiciel de contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui retourne une valeur booléenne à l’option Predicate.

L’exemple suivant filtre les contrôles d’intégrité afin d’exécuter uniquement ceux qui comportent la balise sample :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

Personnaliser le code d’état HTTP

Utilisez ResultStatusCodes pour personnaliser le mappage de l’état d’intégrité aux codes d’état HTTP. Les affectations StatusCodes suivantes sont les valeurs par défaut utilisées par le middleware. Modifiez les valeurs de code d’état selon vos besoins :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

Supprimer les en-têtes de cache

AllowCachingResponses contrôle si l’intergiciel de contrôle d’intégrité ajoute des en-têtes HTTP à une réponse de sonde pour empêcher la mise en cache de la réponse. Si la valeur est false (par défaut), le middleware définit ou substitue les en-têtes Cache-Control, Expires et Pragma afin d’empêcher la mise en cache de la réponse. Si la valeur est true, l’intergiciel ne modifie pas les en-têtes de cache de la réponse :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

Personnaliser la sortie

Pour personnaliser la sortie d’un rapport de contrôle d’intégrité, définissez la propriété HealthCheckOptions.ResponseWriter sur un délégué qui écrit la réponse :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

Le délégué par défaut écrit une réponse minimale constituée de texte en clair, avec la valeur de chaîne HealthReport.Status. Le délégué personnalisé suivant génère une réponse JSON personnalisée à l’aide de System.Text.Json :

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

L’API de contrôle d’intégrité ne fournit pas de prise en charge intégrée pour les formats de retour JSON complexes, car le format est spécifique à votre choix de système de surveillance. Personnalisez la réponse des exemples précédents selon vos besoins. Pour plus d’informations sur la sérialisation JSON avec System.Text.Json, consultez Comment sérialiser et désérialiser JSON dans .NET.

Sonde de base de données

Un contrôle d’intégrité peut spécifier une requête de base de données à exécuter en tant que test booléen pour indiquer si la base de données répond normalement.

AspNetCore.Diagnostics.HealthChecks, une bibliothèque de contrôle d’intégrité pour les applications ASP.NET Core, inclut un contrôle d’intégrité qui s’exécute sur une base de données SQL Server. AspNetCore.Diagnostics.HealthChecks exécute une demande SELECT 1 sur la base de données pour confirmer que la connexion à la base de données est saine.

Avertissement

Lorsque vous vérifiez une connexion de base de données à l’aide d’une requête, choisissez une requête qui est retournée rapidement. L’utilisation d’une requête risque néanmoins d’entraîner une surcharge de la base de données et d’en diminuer les performances. Dans la plupart des cas, il n’est pas nécessaire d’utiliser une requête de test. Il suffit simplement d’établir une connexion à la base de données. Si vous avez besoin d’exécuter une requête, choisissez une requête SELECT simple, telle que SELECT 1.

Pour utiliser ce contrôle d’intégrité de SQL Server, incluez une référence de package au package AspNetCore.HealthChecks.SqlServer NuGet. L’exemple suivant enregistre le contrôle d’intégrité de SQL Server :

builder.Services.AddHealthChecks()
    .AddSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection"));

Remarque

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Sondage DbContext Entity Framework Core

La vérification DbContext confirme que l’application peut communiquer avec la base de données configurée pour un EF CoreDbContext. La vérification DbContext est prise en charge dans les applications qui :

AddDbContextCheck inscrit un contrôle d’intégrité pour un DbContext. Le DbContext est fourni à la méthode en tant que TContext. Une surcharge est disponible pour configurer l’état d’échec, les étiquettes et une requête de test personnalisée.

Par défaut :

  • DbContextHealthCheck appelle la méthode EF Core, CanConnectAsync. Vous pouvez choisir quelle opération doit être exécutée lors du contrôle d’intégrité à l’aide des surcharges de la méthode AddDbContextCheck.
  • Le nom du contrôle d’intégrité correspond à celui du type TContext.

L’exemple suivant enregistre un DbContext et un DbContextHealthCheck associé :

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

Séparer les sondages probe readiness et probe liveness

Dans certains scénarios d’hébergement, une paire de contrôles d’intégrité est utilisée pour déterminer deux états de l’application :

  • La disponibilité indique si l’application s’exécute normalement, sans toutefois être prête à recevoir des requêtes.
  • L’activité indique si une application a cessé de fonctionner et doit être redémarrée.

Examinez l’exemple suivant : une application doit télécharger un fichier de configuration volumineux avant d’être prête à traiter les requêtes. Nous ne souhaitons pas que l’application redémarre si le téléchargement initial échoue, car l’application peut réessayer de télécharger le fichier plusieurs fois. Nous utilisons un probe liveness pour décrire l’activité du processus. Aucune autre vérification n’est exécutée. Nous souhaitons également empêcher l’envoi de requêtes à l’application avant la réussite du téléchargement du fichier de configuration. Nous utilisons un probe readiness pour indiquer un état « non prêt », et ce, jusqu’à ce que le téléchargement ait réussi et que l’application soit prête à recevoir des requêtes.

La tâche en arrière-plan suivante simule un processus de démarrage qui prend environ 15 secondes. Une fois terminée, la tâche définit la propriété StartupHealthCheck.StartupCompleted sur vraie :

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

Le StartupHealthCheck signale l’achèvement de la tâche de démarrage de longue durée et expose la propriété StartupCompleted qui est définie par le service en arrière-plan :

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

Le contrôle d’intégrité est inscrit auprès de AddCheck dans Program.cs en même temps que le service hébergé. Étant donné que le service hébergé doit définir la propriété sur le contrôle d’intégrité, le contrôle d’intégrité est également enregistré dans le conteneur du service en tant que singleton :

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

Pour créer deux points de terminaison de contrôle d’intégrité différents, appelez MapHealthChecks deux fois :

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

L’exemple précédent crée les points de terminaison de contrôle d’intégrité suivants :

  • /healthz/ready pour la vérification de la disponibilité. La vérification de la disponibilité filtre les contrôles d’intégrité pour les éléments avec les balises ready.
  • /healthz/live pour la vérification de l’activité. La vérification de l’activité applique un filtre pour exclure tous les contrôles d’intégrité en retournant false dans le délégué HealthCheckOptions.Predicate. Pour plus d’informations sur le filtrage des contrôles d’intégrité, consultez la section Filtrer les contrôles d’intégrité dans cet article.

Avant l’achèvement de la tâche de démarrage, le point de terminaison /healthz/ready signale un état Unhealthy. Une fois la tâche de démarrage achevée, ce point de terminaison signale un état Healthy. Le point de terminaison /healthz/live exclut tous les contrôles et signale un état Healthy pour tous les appels.

Exemple Kubernetes

Dans un environnement tel que Kubernetes, il peut être utile d’utiliser séparément le test permettant de savoir si la l’application est prête et celui visant à savoir si l’application est active. Dans Kubernetes, une application peut devoir exécuter une tâche de démarrage de longue durée avant d’accepter des requêtes, telle qu’un test de la disponibilité de la base de données sous-jacente. L’utilisation séparée des deux tests permet à l’orchestrateur de faire la distinction entre une application qui fonctionne mais qui n’est pas encore prête, et une application qui n’a pas pu démarrer. Pour plus d’informations sur les sondages probe readiness et probe liveness dans Kubernetes, consultez Configure Liveness and Readiness Probes dans la documentation Kubernetes.

L’exemple suivant montre une configuration probe readiness Kubernetes :

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Distribuer une bibliothèque de contrôle d’intégrité

Pour distribuer une bibliothèque comme un contrôle d’intégrité :

  1. Écrivez un contrôle d’intégrité qui implémente l’interface IHealthCheck comme une classe autonome. La classe peut utiliser une injection de dépendance, une activation de type et des options nommées pour accéder aux données de configuration.

  2. Écrivez une méthode d’extension avec des paramètres que l’application consommatrice appelle dans sa méthode Program.cs. Envisagez l’exemple de contrôle d’intégrité suivant, qui accepte arg1 et arg2 en tant que paramètres de constructeur :

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    La signature précédente indique que le contrôle d’intégrité nécessite des données personnalisées pour traiter la logique du probe de contrôle d’intégrité. Les données sont fournies au délégué qui est utilisé pour créer l’instance de contrôle d’intégrité lorsque le contrôle d’intégrité est inscrit avec une méthode d’extension. Dans l’exemple qui suit, l’appelant spécifie les éléments suivants :

    • arg1 : point de données entier du contrôle d’intégrité.
    • arg2 : argument de chaîne pour le contrôle d’intégrité.
    • name : nom de contrôle d’intégrité facultatif. Une valeur par défaut est utilisée pour null.
    • failureStatus : HealthStatus facultatif, signalé pour un état d’échec. Si null, HealthStatus.Unhealthy est utilisé.
    • tags : collection IEnumerable<string> facultative de balises.
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

Serveur de publication des contrôles d’intégrité

Quand un IHealthCheckPublisher est ajouté au conteneur du service, le système de contrôle d’intégrité exécute régulièrement vos contrôles d’intégrité et appelle PublishAsync avec le résultat. Ce processus est utile dans un scénario impliquant un système de surveillance d’intégrité basé sur les envois (push) qui nécessite que chaque processus appelle le système de surveillance régulièrement afin de déterminer l’état d’intégrité.

HealthCheckPublisherOptions vous autorise à définir les éléments suivants :

  • Delay : retard initial appliqué après le démarrage de l’application avant d’exécuter les instances IHealthCheckPublisher. Le retard est appliqué une seule fois au démarrage et ne s’applique pas aux itérations ultérieures. La valeur par défaut est de cinq secondes.
  • Period : période d’exécution de IHealthCheckPublisher. La valeur par défaut est de 30 secondes.
  • Predicate : si Predicate est null (valeur par défaut), le service de publication du contrôle d’intégrité exécute tous les contrôles d’intégrité enregistrés. Pour exécuter un sous-ensemble de contrôles d’intégrité, fournissez une fonction qui filtre l’ensemble de vérifications. Le prédicat est évalué à chaque période.
  • Timeout : délai d’attente pour l’exécution des contrôles d’intégrité pour toutes les instances IHealthCheckPublisher. Utilisez InfiniteTimeSpan pour une exécution sans délai d’attente. La valeur par défaut est de 30 secondes.

L’exemple suivant montre la disposition d’un éditeur d’intégrité :

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

La classe HealthCheckPublisherOptions fournit les propriétés de configuration du comportement de l’éditeur de contrôle d’intégrité.

L’exemple suivant enregistre un éditeur de contrôle d’intégrité en tant que singleton et configure HealthCheckPublisherOptions :

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

Remarque

AspNetCore.Diagnostics.HealthChecks inclut des éditeurs de plusieurs systèmes, y compris Application Insights.

AspNetCore.Diagnostics.HealthChecks n’est pas géré ni pris en charge par Microsoft.

Injection de dépendances et contrôles d’intégrité

Il est possible d’utiliser l’injection de dépendances pour consommer une instance d’un Type spécifique dans une classe de contrôle d’intégrité. L’injection de dépendances peut être utile pour injecter des options ou une configuration globale dans un contrôle d’intégrité. L’utilisation de l’injection de dépendances n’est pas un scénario courant de la configuration des contrôles d’intégrité. En règle générale, chaque contrôle d’intégrité est assez spécifique au test en question et est configuré à l’aide des méthodes d’extension IHealthChecksBuilder.

L’exemple suivant présente un exemple de contrôle d’intégrité qui récupère un objet de configuration via l’injection de dépendances :

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

Le SampleHealthCheckWithDiConfig et le contrôle d’intégrité doivent être ajoutés au conteneur de service :

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks et MapHealthChecks

Il existe deux façons de rendre les contrôles d’intégrité accessibles aux appelants :

  • UseHealthChecks inscrit l’intergiciel pour gérer les requêtes de contrôle d’intégrité dans le pipeline d’intergiciels.
  • MapHealthChecks inscrit un point de terminaison de contrôle d’intégrité. Le point de terminaison est mis en correspondance et exécuté avec d’autres points de terminaison dans l’application.

Utiliser MapHealthChecks plutôt que UseHealthChecks permet d’utiliser un intergiciel prenant en compte les points de terminaison, comme l’autorisation, et d’avoir un contrôle plus affiné sur la stratégie de correspondance. Utiliser UseHealthChecks plutôt que MapHealthChecks permet principalement de déterminer exactement où les contrôles d’intégrité s’exécutent dans le pipeline d’intergiciel.

UseHealthChecks :

  • Met fin au pipeline quand une requête correspond au point de terminaison de contrôle d’intégrité. Un court-circuit est souvent souhaitable, car il évite le travail inutile, tel que la journalisation et d’autres intergiciels.
  • Sert principalement à configurer l’intergiciel de contrôle d’intégrité dans le pipeline.
  • Peut correspondre à n’importe quel chemin sur un port avec une valeur null ou un élément PathString vide. Autorise l’exécution d’un contrôle d’intégrité sur n’importe quelle requête adressée au port spécifié.
  • Code source

MapHealthChecks autorise :

  • Le mappage d’itinéraires ou de points de terminaison spécifiques pour les contrôles d’intégrité.
  • La personnalisation de l’URL ou du chemin où le point de terminaison de contrôle d’intégrité est accessible.
  • Le mappage de plusieurs points de terminaison de contrôle d’intégrité avec différents itinéraires ou configurations. La prise en charge de plusieurs points de terminaison :
    • Active des points de terminaison distincts pour différents types de contrôles d’intégrité ou de composants.
    • Permet d’établir la distinction entre les différents aspects de l’intégrité de l’application ou d’appliquer des configurations spécifiques à des sous-ensembles de contrôles d’intégrité.
  • Code source

Ressources supplémentaires

Remarque

Cet article a été partiellement créé avec l’aide de l’intelligence artificielle. Avant la publication, un auteur a revu et révisé le contenu, si nécessaire. Voir Nos principes d’utilisation du contenu généré par l’IA dans Microsoft Learn.