Comprobaciones de estado en ASP.NET Core

Por Glenn Condron y Juergen Gutsch

Nota:

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

ASP.NET Core ofrece el middleware de comprobaciones de estado y bibliotecas para informar sobre el estado de los componentes de la infraestructura de la aplicación.

Una aplicación se encarga de exponer las comprobaciones de estado como puntos de conexión HTTP. Los puntos de conexión de las comprobaciones de estado pueden configurarse para diversos escenarios de supervisión en tiempo real:

  • Los orquestadores de contenedores y los equilibradores de carga pueden utilizar los sondeos de estado para comprobar el estado de una aplicación. Por ejemplo, para responder a una comprobación de estado con errores, es posible que un orquestador de contenedores detenga una implementación en curso o reinicie un contenedor. Como respuesta a una aplicación con estado incorrecto, es posible que un equilibrador de carga enrute el tráfico al margen de la instancia con errores hacia una instancia con estado correcto.
  • El uso de la memoria, el disco y otros recursos del servidor físico puede supervisarse para determinar si el estado es correcto.
  • Las comprobaciones de estado pueden probar las dependencias de una aplicación, como las bases de datos y los puntos de conexión de servicio externo, para confirmar la disponibilidad y el funcionamiento normal.

Normalmente, las comprobaciones de estado se usan con un servicio de supervisión externa o un orquestador de contenedores para comprobar el estado de una aplicación. Antes de agregar comprobaciones de estado a una aplicación, debe decidir en qué sistema de supervisión se va a usar. El sistema de supervisión determina qué tipos de comprobaciones de estado se deben crear y cómo configurar sus puntos de conexión.

Sondeo de estado básico

Para muchas aplicaciones, una configuración de sondeo de estado básico que notifique la disponibilidad de la aplicación para procesar las solicitudes (ejecución) es suficiente para detectar el estado de la aplicación.

La configuración básica registra los servicios de comprobación de estado y llama al middleware de comprobaciones de estado para responder a un punto de conexión de dirección URL con una respuesta de estado. De forma predeterminada, no se registran comprobaciones de estado específicas para probar cualquier dependencia o subsistema concretos. La aplicación se considera en buen estado si puede responder en la dirección URL del punto de conexión de mantenimiento. El escritor de respuestas predeterminado escribe HealthStatus como una respuesta de texto no cifrado en el cliente. HealthStatus es HealthStatus.Healthy, HealthStatus.Degraded o HealthStatus.Unhealthy.

Registre los servicios de comprobación de estado con AddHealthChecks de Program.cs. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks.

En el ejemplo siguiente se crea un punto de conexión de comprobación de estado en /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker ofrece una directiva de HEALTHCHECK integrada que puede utilizarse para comprobar el estado de una aplicación que use la configuración de comprobación de estado básica:

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

El ejemplo anterior utiliza curl para hacer una solicitud HTTP al punto de conexión de comprobación de estado en /healthz. curl no se incluye en las imágenes de contenedor de Linux de .NET, pero se puede agregar instalando el paquete necesario en Dockerfile. Los contenedores que usan imágenes basadas en Alpine Linux pueden usar el wget incluido en lugar de curl.

Creación de comprobaciones de estado

Las comprobaciones de estado se crean mediante la implementación de la interfaz de IHealthCheck. El método CheckHealthAsync devuelve un elemento HealthCheckResult que indica el estado como Healthy, Degraded o Unhealthy. El resultado se escribe como una respuesta de texto no cifrado con un código de estado configurable. La configuración se describe en la sección Opciones de comprobación de estado. HealthCheckResult también puede devolver pares clave-valor opcionales.

En el ejemplo siguiente se muestra el diseño de una comprobación de estado:

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 lógica de comprobaciones de estado se coloca en el método CheckHealthAsync. En el ejemplo siguiente se establece una variable ficticia, isHealthy, en true. Si el valor de isHealthy se establece en false, se devuelve el estado HealthCheckRegistration.FailureStatus.

Si CheckHealthAsync produce una excepción durante la comprobación, se devuelve un nuevo HealthReportEntry con su HealthReportEntry.Status establecido en FailureStatus. Este estado se define mediante AddCheck (consulte la sección Registro de los servicios de comprobación de estado) e incluye la excepción interna que produjo el error de comprobación. Description se establece en el mensaje de la excepción.

Registro de los servicios de comprobación de estado

Para registrar un servicio de comprobación de estado, llame a AddCheck en Program.cs:

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

La sobrecarga AddCheck que se muestra en el ejemplo siguiente establece el estado de error (HealthStatus) para notificar cuándo la comprobación de estado informa de un error. Si el estado de error se establece en null (valor predeterminado), HealthStatus.Unhealthy se notifica. Esta sobrecarga es un escenario útil para los creadores de bibliotecas en los que la aplicación ejecuta el estado de error indicado por la biblioteca cuando se produce un error de comprobación de estado si la implementación de la comprobación de estado respeta la configuración.

Las etiquetas se pueden usar para filtrar las comprobaciones de estado. Las etiquetas se describen en la sección Filtrado de comprobaciones de estado.

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

AddCheck también puede ejecutar una función lambda. En el ejemplo siguiente, la comprobación de estado siempre devuelve un resultado correcto:

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

Llame a AddTypeActivatedCheck para pasar argumentos a una implementación de comprobación de estado. En el ejemplo siguiente, una comprobación de estado activada por tipo acepta un entero y una cadena en su constructor:

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."));
    }
}

Para registrar la comprobación de estado anterior, llame a AddTypeActivatedCheck con el entero y la cadena pasados como argumentos:

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

Uso del enrutamiento de comprobaciones de estado

En Program.cs, llame a MapHealthChecks en el generador de puntos de conexiones con la dirección URL del punto de conexión o la ruta de acceso relativa:

app.MapHealthChecks("/healthz");

Requerimiento de host

Llame RequireHost a para especificar uno o más hosts permitidos para el punto de conexión de comprobación de estado. Los hosts deben ser Unicode en lugar de Punycode y pueden incluir un puerto. Si no se proporciona una colección, se acepta cualquier host:

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

Para restringir el punto de conexión de comprobación de estado para que responda solo en un puerto específico, especifique un puerto en la llamada a RequireHost. Este enfoque se usa normalmente en un entorno de contenedor para exponer un puerto para los servicios de supervisión:

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

Advertencia

Las API que se basan en el encabezado host, como HttpRequest.Host y RequireHost, están sujetas a una posible suplantación de identidad por parte de los clientes.

Para evitar la suplantación de identidad de host y puerto, use uno de los métodos siguientes:

Para evitar que los clientes no autorizados suplanten el puerto, llame a RequireAuthorization:

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

Para obtener más información, consulte Comparación de host en rutas con RequireHost.

Requerimiento de autorización

Llame a RequireAuthorization para ejecutar el middleware de autorización en el punto de conexión de solicitudes de comprobación de estado. Una sobrecarga RequireAuthorization acepta una o varias directivas de autorización. Si no se proporciona una directiva, se usa la directiva de autorización predeterminada:

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

Habilitar solicitudes entre orígenes (CORS)

Aunque no se suelen ejecutar comprobaciones de estado manualmente desde un explorador, el middleware de CORS se puede habilitar mediante una llamada a RequireCors en los puntos de conexión de las comprobaciones de estado. La sobrecarga de RequireCors acepta un delegado del generador de directivas CORS (CorsPolicyBuilder) o un nombre de directiva. Para obtener más información, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core.

Opciones de comprobación de estado

El elemento HealthCheckOptions ofrece una oportunidad para personalizar el comportamiento de las comprobaciones de estado:

Filtrado de las comprobaciones de estado

De forma predeterminada, el middleware de comprobaciones de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que devuelva un valor booleano para la opción Predicate.

En el ejemplo siguiente se filtran las comprobaciones de estado para que solo se ejecuten aquellas etiquetadas con sample:

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

Personalización del código de estado HTTP

Use ResultStatusCodes para personalizar la asignación del estado de mantenimiento de los códigos de estado HTTP. Las siguientes asignaciones de StatusCodes son los valores predeterminados que el middleware utiliza. Cambie los valores de código de estado para satisfacer sus necesidades:

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

Supresión de los encabezados de caché

AllowCachingResponses controla si el middleware de comprobaciones de estado agrega encabezados HTTP a una respuesta de sondeo para evitar el almacenamiento en caché de respuesta. Si el valor es false (valor predeterminado), el middleware establece o invalida los encabezados Cache-Control, Expires y Pragma para evitar el almacenamiento en caché de respuesta. Si el valor es true, el middleware no modifica los encabezados de caché de la respuesta:

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

Personalización del resultado

Para personalizar la salida de un informe de comprobaciones de estado, establezca la propiedad HealthCheckOptions.ResponseWriter en un delegado que escriba la respuesta:

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

El delegado predeterminado escribe una respuesta de texto no cifrado mínima con el valor de cadena HealthReport.Status. El siguiente delegado personalizado genera una respuesta JSON personalizada mediante 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()));
}

La API de comprobaciones de estado no ofrece compatibilidad integrada con formatos de retorno JSON complejos porque el formato es específico del sistema de supervisión elegido. Personalice la respuesta en los ejemplos anteriores según sea necesario. Para más información sobre la serialización de JSON con System.Text.Json, consulte Procedimiento para serializar y deserializar JSON en .NET.

Sondeo de bases de datos

Una comprobación de estado puede especificar que una consulta de base de datos se ejecute como una prueba booleana para indicar si esta responde con normalidad.

AspNetCore.Diagnostics.HealthChecks, una biblioteca de comprobación de estado para aplicaciones ASP.NET Core, incluye una comprobación de estado que se ejecuta en una base de datos SQL Server. AspNetCore.Diagnostics.HealthChecks ejecuta una consulta SELECT 1 en la base de datos para confirmar que la conexión a la base de datos es correcta.

Advertencia

Al comprobar la conexión de una base de datos a una consulta, elija una consulta que se devuelva rápidamente. El enfoque de la consulta plantea el riesgo de sobrecargar la base de datos y degradar el rendimiento. En la mayoría de los casos, no es necesario ejecutar una consulta de prueba. Simplemente, realizar una conexión correcta a la base de datos es suficiente. Si resulta necesario ejecutar una consulta, elija una consulta SELECT sencilla, como SELECT 1.

Para utilizar esta comprobación de estado de SQL Server, incluya una referencia al paquete NuGet AspNetCore.HealthChecks.SqlServer. En el ejemplo siguiente se registra la comprobación de estado 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);

Nota

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Sondeo de DbContext de Entity Framework Core

La comprobación DbContext confirma que la aplicación puede comunicarse con la base de datos configurada para un elemento DbContext de EF Core. La comprobación DbContext se admite en las aplicaciones que:

AddDbContextCheck registra una comprobación de estado para un elemento DbContext. El elemento DbContext se proporciona al método como TContext. Hay disponible una sobrecarga para configurar el estado de error, las etiquetas y una consulta de prueba personalizada.

De manera predeterminada:

  • DbContextHealthCheck llama al método CanConnectAsync de EF Core. Se puede personalizar qué operación se ejecuta al comprobar el estado con sobrecargas del método AddDbContextCheck.
  • El nombre de la comprobación de estado es el nombre del tipo TContext.

En el siguiente ejemplo se registra DbContext y un DbContextHealthCheck asociado:

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

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

Sondeos de preparación y ejecución independientes

En algunos escenarios de hospedaje, se usa un par de comprobaciones de estado que distinguen dos estados de la aplicación:

  • Preparación indica si la aplicación se ejecuta con normalidad, pero no está lista para recibir solicitudes.
  • Ejecución indica si una aplicación se ha bloqueado y debe reiniciarse.

Considere el ejemplo siguiente: Antes de estar lista para procesar solicitudes, una aplicación debe descargar un archivo de configuración de gran tamaño. No queremos que se reinicie la aplicación si se produce un error en la descarga inicial, dado que la aplicación puede volver a intentar descargar el archivo varias veces. Usamos un sondeo de ejecución para describir la ejecución del proceso, sin realizar ninguna otra comprobación. También queremos evitar que las solicitudes se envíen a la aplicación antes de que finalice la descarga del archivo de configuración. Hasta que no finaliza la descarga y la aplicación está lista para recibir solicitudes, usamos un sondeo de preparación para indicar un estado "no preparado".

La siguiente tarea en segundo plano simula un proceso de inicio que tarda aproximadamente 15 segundos. Una vez que se completa, la tarea establece la propiedad StartupHealthCheck.StartupCompleted en true:

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;
    }
}

StartupHealthCheck notifica la finalización de la tarea de inicio de ejecución prolongada y expone la propiedad StartupCompleted establecida por el servicio en segundo plano:

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."));
    }
}

La comprobación de estado se registra con AddCheck en Program.cs junto con el servicio hospedado. Dado que el servicio hospedado debe establecer la propiedad en la comprobación de estado, esta también se registra en el contenedor de servicios como singleton:

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

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

Para crear dos puntos de conexión de comprobación de estado diferentes, llame a MapHealthChecks dos veces:

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

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

En el ejemplo anterior se crean los siguientes puntos de conexión de comprobación de estado:

  • /healthz/ready para la comprobación de la idoneidad. La comprobación de preparación filtra las comprobaciones de estado a las etiquetadas con ready.
  • /healthz/live para la comprobación de la ejecución. La comprobación de ejecución filtra todas las comprobaciones de estado devolviendo false en el delegado HealthCheckOptions.Predicate. Para obtener más información sobre el filtrado de comprobaciones de estado, vea Filtrado de las comprobaciones de estado en este artículo.

Antes de que se complete la tarea de inicio, el punto de conexión /healthz/ready notifica un estado Unhealthy. Después de que se complete la tarea de inicio, este punto de conexión notifica un estado Healthy. El punto de conexión /healthz/live excluye todas las comprobaciones e informa de un estado Healthy para todas las llamadas.

Ejemplo de Kubernetes

Utilizar comprobaciones de preparación y ejecución independientes es útil en un entorno como Kubernetes. En Kubernetes, es posible que se requiera una aplicación para ejecutar un trabajo de inicio lento antes de aceptar solicitudes, como una prueba de la disponibilidad de la base de datos subyacente. El hecho de utilizar comprobaciones independientes permite que el orquestador distinga si la aplicación está funcionando, pero aún no esté preparada, o si la aplicación no se ha podido iniciar. Para obtener más información sobre los sondeos de preparación y ejecución en Kubernetes, consulte Configuración de sondeos de preparación y ejecución en la documentación de Kubernetes.

En el ejemplo siguiente, se muestra una configuración de sondeo de preparación de 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

Distribución de una biblioteca de comprobación de estado

Para distribuir una comprobación de estado como una biblioteca, haga lo siguiente:

  1. Escriba una comprobación de estado que implemente la interfaz de IHealthCheck como una clase independiente. La clase puede depender de la inserción de dependencias (DI), de la activación del tipo y de las opciones denominadas para acceder a los datos de configuración.

  2. Escriba un método de extensión con los parámetros a los que la aplicación de uso llama en su método Program.cs. Considere la siguiente comprobación de estado de ejemplo, que acepta arg1 y arg2 como parámetros de constructor:

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

    La firma anterior indica que la comprobación de estado requiere datos personalizados para procesar la lógica de sondeo de la comprobación de estado. Los datos se proporcionan al delegado que se usa para crear la instancia de la comprobación de estado cuando la comprobación de estado se registra con un método de extensión. En el ejemplo siguiente, el autor de la llamada especifica:

    • arg1: punto de datos de entero para la comprobación de estado.
    • arg2: argumento de cadena para la comprobación de estado.
    • name: nombre de comprobación de estado opcional. Si null, se usa el valor predeterminado.
    • failureStatus: un HealthStatus opcional, que se notifica para un estado de error. En el caso de null, se utiliza HealthStatus.Unhealthy.
    • tags: una colección IEnumerable<string> opcional de etiquetas.
    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));
        }
    }
    

Publicador de la comprobación de estado

Cuando un elemento IHealthCheckPublisher se agrega al contenedor de servicios, el sistema de comprobación de estado ejecuta periódicamente las comprobaciones de estado y llama a PublishAsync con el resultado. Este proceso es útil en un escenario de sistema de supervisión de estado basado en inserción que espera que cada proceso llame periódicamente al sistema de supervisión para determinar el estado.

HealthCheckPublisherOptions le permiten establecer:

  • Delay: el retraso inicial aplicado tras iniciarse la aplicación antes de ejecutar instancias de IHealthCheckPublisher. El retraso se aplica una vez en el inicio y no se aplica a iteraciones posteriores. El valor predeterminado es cinco segundos.
  • Period: el período de ejecución de IHealthCheckPublisher. El valor predeterminado es 30 segundos.
  • Predicate: si Predicate es null (valor predeterminado), el servicio de publicador de la comprobación de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que filtre el conjunto de comprobaciones. El predicado se evalúa cada período.
  • Timeout: el tiempo de expiración para ejecutar las comprobaciones de estado para todas las instancias de IHealthCheckPublisher. Use InfiniteTimeSpan para ejecutar sin tiempo de expiración. El valor predeterminado es 30 segundos.

En el ejemplo siguiente se muestra el diseño de un publicador de estado:

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

        return Task.CompletedTask;
    }
}

La clase HealthCheckPublisherOptions proporciona propiedades para configurar el comportamiento del publicador de la comprobación de estado.

En el ejemplo siguiente se registra un publicador de comprobación de estado como singleton y se configura 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:

  • incluye editores para varios sistemas, incluido Application Insights.
  • Microsoft no realiza su mantenimiento ni su soporte técnico.

Comprobaciones de estado individuales

Delay y Period se pueden establecer en cada HealthCheckRegistration individualmente. Esto resulta útil cuando desea ejecutar algunas comprobaciones de estado a una velocidad diferente del período establecido en HealthCheckPublisherOptions.

El siguiente código establece Delay y Period para 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();

Inserción de dependencias y comprobaciones de estado

Se puede usar la inserción de dependencias para consumir una instancia de un elemento Type específico dentro de una clase de comprobación de estado (Health Check). La inserción de dependencias puede ser útil para insertar opciones o una configuración global en una comprobación de estado. El uso de la inserción de dependencias no es un escenario común para configurar comprobaciones de estado. Normalmente, cada comprobación de estado es bastante específica para la prueba real y se configura mediante métodos de extensión IHealthChecksBuilder.

En el ejemplo siguiente se muestra una comprobación de estado de ejemplo que recupera un objeto de configuración a través de la inserción de dependencias:

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."));
    }
}

El elemento SampleHealthCheckWithDiConfig y la comprobación de estado deben agregarse al contenedor de servicios:

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 frente a MapHealthChecks

Hay dos maneras de que las comprobaciones de estado sean accesibles para los autores de llamadas:

  • UseHealthChecks registra el middleware para controlar las solicitudes de comprobaciones de estado en la canalización de middleware.
  • MapHealthChecks registra un punto de conexión de comprobaciones de estado. El punto de conexión coincide y se ejecuta junto con otros puntos de conexión de la aplicación.

La ventaja de usar MapHealthChecks sobre UseHealthChecks es la capacidad de usar middleware compatible con puntos de conexión, como la autorización, y tener un mayor control específico sobre la directiva de coincidencias. La principal ventaja de usar UseHealthChecks sobre MapHealthChecks es controlar exactamente dónde se ejecutan las comprobaciones de estado en la canalización de middleware.

UseHealthChecks:

  • Finaliza la canalización cuando una solicitud coincide con el punto de conexión de comprobación de estado. Un cortocircuito suele ser deseable porque evita el trabajo innecesario, como el registro y otro middleware.
  • Se usa principalmente para configurar el middleware de las comprobaciones de estado en la canalización.
  • Puede coincidir con cualquier ruta de acceso de un puerto con un null o PathString vacío. Permite realizar una comprobación de estado en cualquier solicitud realizada al puerto especificado.
  • Código fuente

MapHealthChecks permite:

  • Finalizar la canalización cuando una solicitud coincide con el punto de conexión de comprobación de estado, llamando a ShortCircuit. Por ejemplo: app.MapHealthChecks("/healthz").ShortCircuit();. Para obtener más información, vea Middleware de cortocircuito después del enrutamiento.
  • Asignar rutas o puntos de conexión específicos para las comprobaciones de estado.
  • Personalización de la dirección URL o ruta de acceso a la que se puede acceder al punto de conexión de la comprobación de estado.
  • Asignación de varios puntos de conexión de la comprobación de estado con diferentes rutas o configuraciones. Compatibilidad con varios puntos de conexión:
    • Habilita puntos de conexión independientes para distintos tipos de comprobaciones de estado o componentes.
    • Se usa para diferenciar entre distintos aspectos del estado de la aplicación o aplicar configuraciones específicas a subconjuntos de comprobaciones de estado.
  • Código fuente

Recursos adicionales

Nota:

Este artículo se ha creado parcialmente con ayuda de inteligencia artificial. Antes de la publicación, un autor ha revisado y corregido el contenido según ha estimado necesario. Consulta Los principios para usar contenido generado por IA en Microsoft Learn.

ASP.NET Core ofrece el middleware de comprobaciones de estado y bibliotecas para informar sobre el estado de los componentes de la infraestructura de la aplicación.

Una aplicación se encarga de exponer las comprobaciones de estado como puntos de conexión HTTP. Los puntos de conexión de las comprobaciones de estado pueden configurarse para diversos escenarios de supervisión en tiempo real:

  • Los orquestadores de contenedores y los equilibradores de carga pueden utilizar los sondeos de estado para comprobar el estado de una aplicación. Por ejemplo, para responder a una comprobación de estado con errores, es posible que un orquestador de contenedores detenga una implementación en curso o reinicie un contenedor. Como respuesta a una aplicación con estado incorrecto, es posible que un equilibrador de carga enrute el tráfico al margen de la instancia con errores hacia una instancia con estado correcto.
  • El uso de la memoria, el disco y otros recursos del servidor físico puede supervisarse para determinar si el estado es correcto.
  • Las comprobaciones de estado pueden probar las dependencias de una aplicación, como las bases de datos y los puntos de conexión de servicio externo, para confirmar la disponibilidad y el funcionamiento normal.

Vea o descargue el código de ejemplo (cómo descargarlo)

La aplicación de ejemplo incluye ejemplos de los escenarios descritos en este artículo. Para ejecutar la aplicación de ejemplo para un escenario determinado, use el comando dotnet run desde la carpeta del proyecto en un shell de comandos. Para obtener información sobre cómo utilizar la aplicación de ejemplo, consulte el archivo README.md de la aplicación de ejemplo y las descripciones de escenarios de este tema.

Requisitos previos

Normalmente, las comprobaciones de estado se usan con un servicio de supervisión externa o un orquestador de contenedores para comprobar el estado de una aplicación. Antes de agregar comprobaciones de estado a una aplicación, debe decidir en qué sistema de supervisión se va a usar. El sistema de supervisión determina qué tipos de comprobaciones de estado se deben crear y cómo configurar sus puntos de conexión.

Se ha referencia al paquete Microsoft.AspNetCore.Diagnostics.HealthChecks de forma implícita para las aplicaciones ASP.NET Core. Para ejecutar comprobaciones de estado con Entity Framework Core, agregue una referencia al paquete Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

La aplicación de ejemplo proporciona código de inicio para mostrar las comprobaciones de estado para varios escenarios. En el escenario sondeo de base de datos se comprueba el estado de una conexión de base de datos mediante AspNetCore.Diagnostics.HealthChecks. El escenario de sondeo de DbContext comprueba una base de datos mediante un elemento DbContext de EF Core. Para explorar los escenarios de la base de datos, la aplicación de ejemplo:

Nota:

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Otro escenario de comprobación de estado muestra cómo filtrar las comprobaciones de estado por un puerto de administración. La aplicación de ejemplo requiere la creación de un archivo Properties/launchSettings.json que incluya la dirección URL de administración y el puerto de administración. Para obtener más información, consulte la sección Filtrado por puerto.

Sondeo de estado básico

Para muchas aplicaciones, una configuración de sondeo de estado básico que notifique la disponibilidad de la aplicación para procesar las solicitudes (ejecución) es suficiente para detectar el estado de la aplicación.

La configuración básica registra los servicios de comprobación de estado y llama al middleware de comprobaciones de estado para responder a un punto de conexión de dirección URL con una respuesta de estado. De forma predeterminada, no se registran comprobaciones de estado específicas para probar cualquier dependencia o subsistema concretos. La aplicación se considera en buen estado si puede responder en la dirección URL del punto de conexión de mantenimiento. El escritor de respuesta predeterminado escribe el estado (HealthStatus) como respuesta de texto no cifrado en el cliente, que indica un estado HealthStatus.Healthy, HealthStatus.Degraded o HealthStatus.Unhealthy.

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure.

En la aplicación de ejemplo, el punto de conexión de la comprobación de estado se crea en /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");
        });
    }
}

Para ejecutar el escenario de configuración básica mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario basic

Ejemplo de Docker

Docker ofrece una directiva de HEALTHCHECK integrada que puede utilizarse para comprobar el estado de una aplicación que use la configuración de comprobación de estado básica:

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

Creación de comprobaciones de estado

Las comprobaciones de estado se crean mediante la implementación de la interfaz de IHealthCheck. El método CheckHealthAsync devuelve un elemento HealthCheckResult que indica el estado como Healthy, Degraded o Unhealthy. El resultado se escribe como una respuesta de texto no cifrado con un código de estado configurable. (La configuración se describe en la sección Opciones de comprobación de estado). HealthCheckResult también puede devolver pares clave-valor opcionales.

La siguiente clase ExampleHealthCheck muestra el diseño de una comprobación de estado. La lógica de comprobaciones de estado se coloca en el método CheckHealthAsync. En el ejemplo siguiente se establece una variable ficticia, healthCheckResultHealthy, en true. Si el valor de healthCheckResultHealthy se establece en false, se devuelve el estado HealthCheckRegistration.FailureStatus.

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 inicia una excepción durante la comprobación, se devuelve una nueva instancia de HealthReportEntry con HealthReportEntry.Status establecido en FailureStatus, que se define mediante AddCheck (vea la sección Registrar de servicios de comprobación de estado) e incluye la excepción interna que ha provocado inicialmente el error de comprobación. Description se establece en el mensaje de la excepción.

Registro de los servicios de comprobación de estado

El tipo ExampleHealthCheck se agrega a los servicios de comprobación de estado con AddCheck en Startup.ConfigureServices:

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

La sobrecarga AddCheck que se muestra en el ejemplo siguiente establece el estado de error (HealthStatus) para notificar cuándo la comprobación de estado informa de un error. Si el estado de error se establece en null (valor predeterminado), HealthStatus.Unhealthy se notifica. Esta sobrecarga es un escenario útil para los creadores de bibliotecas en los que la aplicación ejecuta el estado de error indicado por la biblioteca cuando se produce un error de comprobación de estado si la implementación de la comprobación de estado respeta la configuración.

Las etiquetas pueden usarse para filtrar las comprobaciones de estado, que se describen con más detalle en la sección Filtrado de las comprobaciones de estado.

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

AddCheck también puede ejecutar una función lambda. En el ejemplo siguiente, el nombre de la comprobación de estado se especifica como Example y la comprobación siempre devuelve un estado correcto:

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

Llame a AddTypeActivatedCheck para pasar argumentos a una implementación de comprobación de estado. En el ejemplo siguiente, TestHealthCheckWithArgs acepta un entero y una cadena que se van a usar cuando se llame a CheckHealthAsync:

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 se registra mediante un llamado a AddTypeActivatedCheck con el entero y la cadena que se pasaron a la implementación:

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

Uso del enrutamiento de comprobaciones de estado

En Startup.Configure, llame a MapHealthChecks en el generador de puntos de conexiones con la dirección URL del punto de conexión o la ruta de acceso relativa:

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

Requerimiento de host

Llame RequireHost a para especificar uno o más hosts permitidos para el punto de conexión de comprobación de estado. Los hosts deben ser Unicode en lugar de Punycode y pueden incluir un puerto. Si no se proporciona una colección, se acepta cualquier host.

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

Para obtener más información, consulte la sección Filtrado por puerto.

Requerimiento de autorización

Llame a RequireAuthorization para ejecutar el middleware de autorización en el punto de conexión de solicitudes de comprobación de estado. Una sobrecarga RequireAuthorization acepta una o varias directivas de autorización. Si no se proporciona una directiva, se usa la directiva de autorización predeterminada.

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

Habilitar solicitudes entre orígenes (CORS)

Aunque no se suelen ejecutar comprobaciones de estado manualmente desde un explorador, el middleware de CORS se puede habilitar mediante una llamada a RequireCors en los puntos de conexión de las comprobaciones de estado. Una sobrecarga RequireCors acepta un delegado del generador de directivas CORS (CorsPolicyBuilder) o un nombre de directiva. Si no se proporciona una directiva, se usa la directiva CORS predeterminada. Para obtener más información, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core.

Opciones de comprobación de estado

El elemento HealthCheckOptions ofrece una oportunidad para personalizar el comportamiento de las comprobaciones de estado:

Filtrado de las comprobaciones de estado

De forma predeterminada, el middleware de comprobaciones de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que devuelva un valor booleano para la opción Predicate. En el ejemplo siguiente, la etiqueta (bar_tag) de la comprobación de estado Bar la filtra, en la instrucción condicional de la función, donde true solo se devuelve si la propiedad Tags de la comprobación de estado coincide con foo_tag o baz_tag:

En 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" });

En Startup.Configure, el Predicate filtra la comprobación de estado "Bar". Solo se ejecutan Foo y Baz:

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

Personalización del código de estado HTTP

Use ResultStatusCodes para personalizar la asignación del estado de mantenimiento de los códigos de estado HTTP. Las siguientes asignaciones de StatusCodes son los valores predeterminados que el middleware utiliza. Cambie los valores de código de estado para satisfacer sus necesidades.

En Startup.Configure:

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

Supresión de los encabezados de caché

AllowCachingResponses controla si el middleware de comprobaciones de estado agrega encabezados HTTP a una respuesta de sondeo para evitar el almacenamiento en caché de respuesta. Si el valor es false (valor predeterminado), el middleware establece o invalida los encabezados Cache-Control, Expires y Pragma para evitar el almacenamiento en caché de respuesta. Si el valor es true, el middleware no modifica los encabezados de caché de la respuesta.

En Startup.Configure:

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

Personalización del resultado

En Startup.Configure, establezca la opción HealthCheckOptions.ResponseWriter en un delegado para escribir la respuesta:

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

El delegado predeterminado escribe una respuesta de texto no cifrado mínima con el valor de cadena HealthReport.Status. Los siguientes delegados personalizados generan una respuesta JSON personalizada.

En el primer ejemplo de la aplicación de ejemplo se muestra cómo usar 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);
    }
}

En el segundo ejemplo se muestra cómo usar 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));
}

En la aplicación de ejemplo, convierta en comentario la SYSTEM_TEXT_JSONdirectiva de preprocesador en CustomWriterStartup.csCustomWriterStartup.cs para habilitar la versión Newtonsoft.Json de WriteResponse.

La API de comprobaciones de estado no ofrece compatibilidad integrada con formatos de retorno JSON complejos porque el formato es específico del sistema de supervisión elegido. Personalice la respuesta en los ejemplos anteriores según sea necesario. Para más información sobre la serialización de JSON con System.Text.Json, consulte Procedimiento para serializar y deserializar JSON en .NET.

Sondeo de bases de datos

Una comprobación de estado puede especificar que una consulta de base de datos se ejecute como una prueba booleana para indicar si esta responde con normalidad.

En la aplicación de ejemplo se usa AspNetCore.Diagnostics.HealthChecks, una biblioteca de comprobaciones de estado para las aplicaciones de ASP.NET Core, a fin de ejecutar una comprobación de estado en una base de datos de SQL Server. AspNetCore.Diagnostics.HealthChecks ejecuta una consulta SELECT 1 en la base de datos para confirmar que la conexión a la base de datos es correcta.

Advertencia

Al comprobar la conexión de una base de datos a una consulta, elija una consulta que se devuelva rápidamente. El enfoque de la consulta plantea el riesgo de sobrecargar la base de datos y degradar el rendimiento. En la mayoría de los casos, no es necesario ejecutar una consulta de prueba. Simplemente, realizar una conexión correcta a la base de datos es suficiente. Si resulta necesario ejecutar una consulta, elija una consulta SELECT sencilla, como SELECT 1.

Incluya una referencia de paquete a AspNetCore.HealthChecks.SqlServer.

Proporcione una cadena de conexión a base de datos válida en el archivo appsettings.json de la aplicación de ejemplo. La aplicación usa una base de datos de SQL Server denominada 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": "*"
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. La aplicación de ejemplo llama al método AddSqlServer con la cadena de conexión de la base de datos (DbHealthStartup.cs):

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure:

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

Para ejecutar el escenario de sondeo de base de datos mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario db

Nota

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Sondeo de DbContext de Entity Framework Core

La comprobación DbContext confirma que la aplicación puede comunicarse con la base de datos configurada para un elemento DbContext de EF Core. La comprobación DbContext se admite en las aplicaciones que:

AddDbContextCheck<TContext> registra una comprobación de estado para un elemento DbContext. El elemento DbContext se proporciona como TContext en el método. Hay disponible una sobrecarga para configurar el estado de error, las etiquetas y una consulta de prueba personalizada.

De manera predeterminada:

  • DbContextHealthCheck llama al método CanConnectAsync de EF Core. Se puede personalizar qué operación se ejecuta al comprobar el estado con sobrecargas del método AddDbContextCheck.
  • El nombre de la comprobación de estado es el nombre del tipo TContext.

En la aplicación de ejemplo, se proporciona AppDbContext para AddDbContextCheck y se registra como un servicio en Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure:

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

Para ejecutar el escenario de sondeo de DbContext mediante la aplicación de ejemplo, confirme que la base de datos que la cadena de conexión especifica no exista en la instancia de SQL Server. Si la base de datos existe, elimínela.

Ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario dbcontext

Cuando la aplicación ya se esté ejecutando, compruebe el estado de mantenimiento mediante una solicitud al punto de conexión /health en un explorador. La base de datos y AppDbContext no existen, por lo que la aplicación proporciona la respuesta siguiente:

Unhealthy

Active la aplicación de ejemplo para crear la base de datos. Realice una solicitud a /createdatabase. La aplicación responde:

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

Realice una solicitud al punto de conexión /health. La base de datos y el contexto existen, por lo que la aplicación responde:

Healthy

Active la aplicación de ejemplo para eliminar la base de datos. Realice una solicitud a /deletedatabase. La aplicación responde:

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

Realice una solicitud al punto de conexión /health. La aplicación proporciona una respuesta incorrecta:

Unhealthy

Sondeos de preparación y ejecución independientes

En algunos escenarios de hospedaje, se usa un par de comprobaciones de estado que distinguen dos estados de la aplicación:

  • Preparación indica si la aplicación se ejecuta con normalidad, pero no está lista para recibir solicitudes.
  • Ejecución indica si una aplicación se ha bloqueado y debe reiniciarse.

Considere el ejemplo siguiente: Antes de estar lista para procesar solicitudes, una aplicación debe descargar un archivo de configuración de gran tamaño. No queremos que se reinicie la aplicación si se produce un error en la descarga inicial, dado que la aplicación puede volver a intentar descargar el archivo varias veces. Usamos un sondeo de ejecución para describir la ejecución del proceso, sin realizar ninguna otra comprobación. También queremos evitar que las solicitudes se envíen a la aplicación antes de que finalice la descarga del archivo de configuración. Hasta que no finaliza la descarga y la aplicación está lista para recibir solicitudes, usamos un sondeo de preparación para indicar un estado "no preparado".

La aplicación de ejemplo contiene una comprobación de estado para notificar la finalización de la tarea de inicio de ejecución prolongada en un servicio hospedado. El elemento StartupHostedServiceHealthCheck expone una propiedad, StartupTaskCompleted, que el servicio hospedado puede establecer en true al terminar su tarea de ejecución prolongada (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."));
    }
}

Un servicio hospedado (Services/StartupHostedService) se encarga de iniciar la tarea en segundo plano de larga ejecución. Al finalizar la tarea, StartupHostedServiceHealthCheck.StartupTaskCompleted se establece en 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()
    {
    }
}

La comprobación de estado se registra con AddCheck en Startup.ConfigureServices junto con el servicio hospedado. Dado que el servicio hospedado debe establecer la propiedad en la comprobación de estado, esta también se registra en el contenedor de servicios (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>();

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure. En la aplicación de ejemplo, los puntos de conexión de la comprobación de estado se crean en:

  • /health/ready para la comprobación de la idoneidad. La comprobación de preparación filtra las comprobaciones de estado con la etiqueta ready.
  • /health/live para la comprobación de la ejecución. La comprobación de ejecución filtra el elemento StartupHostedServiceHealthCheck devolviendo false en HealthCheckOptions.Predicate (para obtener más información, vea Filtrado de las comprobaciones de estado).

En el código de ejemplo siguiente:

  • La comprobación de preparación usa todas las comprobaciones registradas con la etiqueta "ready".
  • Predicate excluye todas las comprobaciones y devuelve una respuesta de que todo está correcto (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
    });
}

Para ejecutar el escenario de configuración de la preparación/ejecución mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario liveness

En un explorador, visite /health/ready varias veces hasta que hayan pasado 15 segundos. La comprobación de estado notifica un estado Unhealthy durante los primeros 15 segundos. Pasados 15 segundos, el punto de conexión notifica un estado Healthy, lo que indica que el servicio hospedado ya ha finalizado la tarea de ejecución prolongada.

En este ejemplo también se crea un publicador de la comprobación de estado (implementación IHealthCheckPublisher) que ejecuta la primera comprobación de preparación con un retraso de dos segundos. Para obtener más información, consulte la sección Publicador de la comprobación de estado.

Ejemplo de Kubernetes

Utilizar comprobaciones de preparación y ejecución independientes es útil en un entorno como Kubernetes. En Kubernetes, es posible que se requiera una aplicación para ejecutar un trabajo de inicio lento antes de aceptar solicitudes, como una prueba de la disponibilidad de la base de datos subyacente. El hecho de utilizar comprobaciones independientes permite que el orquestador distinga si la aplicación está funcionando, pero aún no esté preparada, o si la aplicación no se ha podido iniciar. Para obtener más información sobre los sondeos de preparación y ejecución en Kubernetes, consulte Configuración de sondeos de preparación y ejecución en la documentación de Kubernetes.

En el ejemplo siguiente, se muestra una configuración de sondeo de preparación de 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

Sondeo basado en métrica con un escritor de respuesta personalizada

La aplicación de ejemplo muestra una comprobación de estado de memoria con un escritor de respuesta personalizada.

MemoryHealthCheck notifica un estado degradado si la aplicación usa más de un umbral de memoria determinado (1 GB en la aplicación de ejemplo). El elemento HealthCheckResult incluye información del recolector de elementos no utilizados (GC) de la aplicación (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));
    }
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. En lugar de pasar la comprobación de estado a AddCheck para habilitarla, MemoryHealthCheck se registra como servicio. Todos los servicios registrados de IHealthCheck están disponibles para los servicios de comprobación de estado y middleware. Se recomienda registrar los servicios de comprobación de estado como los servicios de Singleton.

En CustomWriterStartup.cs de la aplicación de ejemplo:

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure. Se proporciona un delegado de WriteResponse a la propiedad ResponseWriter para generar una respuesta JSON personalizada al ejecutarse la comprobación de estado:

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

El delegado WriteResponse da a CompositeHealthCheckResult el formato de objeto JSON y suspende el resultado de JSON para la respuesta de comprobación de estado. Para más información, consulte la sección Personalización del resultado.

Para ejecutar el sondeo basado en métrica con el resultado de un escritor de respuesta personalizada mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario writer

Nota

AspNetCore.Diagnostics.HealthChecks incluye escenarios de comprobación de estado basados en métricas, como las comprobaciones del almacenamiento del disco y de ejecución de máximo valor.

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Filtrado por puerto

Llame a RequireHost en MapHealthChecks con un patrón de dirección URL que especifique un puerto para restringir las solicitudes de comprobación de estado al puerto especificado. Este enfoque se usa normalmente en un entorno de contenedor para exponer un puerto para los servicios de supervisión.

La aplicación de ejemplo configura el puerto con el proveedor de configuración de variable de entorno. El puerto se establece en el archivo launchSettings.json y se pasa al proveedor de configuración a través de una variable de entorno. También debe configurar el servidor para que escuche las solicitudes en el puerto de administración.

Para utilizar la aplicación de ejemplo para que muestre la configuración del puerto de administración, cree el archivo launchSettings.json en una carpeta Properties.

El archivo Properties/launchSettings.json siguiente de la aplicación de ejemplo no se incluye en los archivos de proyecto de la aplicación de ejemplo y se debe crear manualmente:

{
  "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/"
    }
  }
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure.

En la aplicación de ejemplo, una llamada a RequireHost en el punto de conexión Startup.Configure especifica el puerto de administración de la configuración:

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

Los puntos de conexión se crean en la aplicación de ejemplo en Startup.Configure. En el código de ejemplo siguiente:

  • La comprobación de preparación usa todas las comprobaciones registradas con la etiqueta "ready".
  • Predicate excluye todas las comprobaciones y devuelve una respuesta de que todo está correcto (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
    });
}

Nota

Para evitar la creación del archivo launchSettings.json en la aplicación de ejemplo, configure el puerto de administración explícitamente en código. En Program.cs, donde se crea HostBuilder, agregue una llamada a ListenAnyIP y proporcione el punto de conexión del puerto de administración de la aplicación. En Configure de ManagementPortStartup.cs, especifique el puerto de administración con 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");
});

Para ejecutar el escenario de configuración del puerto de administración mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario port

Distribución de una biblioteca de comprobación de estado

Para distribuir una comprobación de estado como una biblioteca, haga lo siguiente:

  1. Escriba una comprobación de estado que implemente la interfaz de IHealthCheck como una clase independiente. La clase puede depender de la inserción de dependencias (DI), de la activación del tipo y de las opciones denominadas para acceder a los datos de configuración.

    En la lógica de comprobaciones de estado de CheckHealthAsync:

    • data1 y data2 se usan en el método para ejecutar la lógica de comprobación de estado del sondeo.
    • Se controla AccessViolationException.

    Cuando se produce un AccessViolationException, se devuelve FailureStatus con HealthCheckResult para permitir que los usuarios configuren el estado de error de las comprobaciones de estado.

    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. Escriba un método de extensión con los parámetros a los que la aplicación de uso llama en su método Startup.Configure. En el ejemplo siguiente, suponga que existe la siguiente firma del método de comprobación de estado:

    ExampleHealthCheck(string, string, int )
    

    La firma anterior indica que la ExampleHealthCheck requiere datos adicionales para procesar la lógica de sondeo de la comprobación de estado. Los datos se proporcionan al delegado que se usa para crear la instancia de la comprobación de estado cuando la comprobación de estado se registra con un método de extensión. En el ejemplo siguiente, el autor de llamada especifica los siguientes elementos opcionales:

    • nombre de la comprobación de estado (name). En el caso de null, se utiliza example_health_check.
    • punto de datos de cadena para la comprobación de estado (data1).
    • punto de datos enteros para la comprobación de estado (data2). En el caso de null, se utiliza 1.
    • estado de error (HealthStatus). De manera predeterminada, es null. Si se utiliza null, HealthStatus.Unhealthy se notifica para un estado de error.
    • etiquetas (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));
        }
    }
    

Publicador de la comprobación de estado

Cuando un elemento IHealthCheckPublisher se agrega al contenedor de servicios, el sistema de comprobación de estado ejecuta periódicamente las comprobaciones de estado y llama a PublishAsync con el resultado. Esto es útil en un escenario de sistema de seguimiento de estado basado en inserción en el que se espera que cada proceso llame periódicamente al sistema de seguimiento con el fin de determinar el estado.

La interfaz de IHealthCheckPublisher tiene un único método:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions le permiten establecer:

  • Delay: el retraso inicial aplicado tras iniciarse la aplicación antes de ejecutar instancias de IHealthCheckPublisher. El retraso se aplica una vez durante el inicio y no se aplica a las iteraciones posteriores. El valor predeterminado es cinco segundos.
  • Period: el período de ejecución de IHealthCheckPublisher. El valor predeterminado es 30 segundos.
  • Predicate: si Predicate es null (valor predeterminado), el servicio de publicador de la comprobación de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que filtre el conjunto de comprobaciones. El predicado se evalúa cada período.
  • Timeout: el tiempo de expiración para ejecutar las comprobaciones de estado para todas las instancias de IHealthCheckPublisher. Use InfiniteTimeSpan para ejecutar sin tiempo de expiración. El valor predeterminado es 30 segundos.

En la aplicación de ejemplo, ReadinessPublisher es una implementación de IHealthCheckPublisher. El estado de comprobación de estado se registra para cada comprobación en un nivel de registro de:

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;
    }
}

En el ejemplo LivenessProbeStartup de la aplicación de ejemplo, la comprobación de preparación StartupHostedService tiene un retraso de inicio de dos segundos y ejecuta la comprobación cada 30 segundos. Para activar la implementación de IHealthCheckPublisher, el ejemplo registra ReadinessPublisher como servicio singleton en el contenedor de inserción de dependencias (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>();

Nota:

AspNetCore.Diagnostics.HealthChecks incluye editores para varios sistemas, incluido Application Insights.

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Restricción de las comprobaciones de estado con MapWhen

Use MapWhen para crear de forma condicional una rama de la canalización de solicitudes para los puntos de conexión de comprobación del estado.

En el ejemplo siguiente, MapWhen crea una rama de la canalización de solicitudes para activar el middleware de comprobaciones de estado si se recibe una solicitud GET para el punto de conexión 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();
});

Para obtener más información, consulte Middleware de ASP.NET Core.

ASP.NET Core ofrece el middleware de comprobaciones de estado y bibliotecas para informar sobre el estado de los componentes de la infraestructura de la aplicación.

Una aplicación se encarga de exponer las comprobaciones de estado como puntos de conexión HTTP. Los puntos de conexión de las comprobaciones de estado pueden configurarse para diversos escenarios de supervisión en tiempo real:

  • Los orquestadores de contenedores y los equilibradores de carga pueden utilizar los sondeos de estado para comprobar el estado de una aplicación. Por ejemplo, para responder a una comprobación de estado con errores, es posible que un orquestador de contenedores detenga una implementación en curso o reinicie un contenedor. Como respuesta a una aplicación con estado incorrecto, es posible que un equilibrador de carga enrute el tráfico al margen de la instancia con errores hacia una instancia con estado correcto.
  • El uso de la memoria, el disco y otros recursos del servidor físico puede supervisarse para determinar si el estado es correcto.
  • Las comprobaciones de estado pueden probar las dependencias de una aplicación, como las bases de datos y los puntos de conexión de servicio externo, para confirmar la disponibilidad y el funcionamiento normal.

Vea o descargue el código de ejemplo (cómo descargarlo)

La aplicación de ejemplo incluye ejemplos de los escenarios descritos en este artículo. Para ejecutar la aplicación de ejemplo para un escenario determinado, use el comando dotnet run desde la carpeta del proyecto en un shell de comandos. Para obtener información sobre cómo utilizar la aplicación de ejemplo, consulte el archivo README.md de la aplicación de ejemplo y las descripciones de escenarios de este tema.

Requisitos previos

Normalmente, las comprobaciones de estado se usan con un servicio de supervisión externa o un orquestador de contenedores para comprobar el estado de una aplicación. Antes de agregar comprobaciones de estado a una aplicación, debe decidir en qué sistema de supervisión se va a usar. El sistema de supervisión determina qué tipos de comprobaciones de estado se deben crear y cómo configurar sus puntos de conexión.

Se ha referencia al paquete Microsoft.AspNetCore.Diagnostics.HealthChecks de forma implícita para las aplicaciones ASP.NET Core. Para ejecutar comprobaciones de estado con Entity Framework Core, agregue una referencia al paquete Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

La aplicación de ejemplo proporciona código de inicio para mostrar las comprobaciones de estado para varios escenarios. En el escenario sondeo de base de datos se comprueba el estado de una conexión de base de datos mediante AspNetCore.Diagnostics.HealthChecks. El escenario de sondeo de DbContext comprueba una base de datos mediante un elemento DbContext de EF Core. Para explorar los escenarios de la base de datos, la aplicación de ejemplo:

Nota:

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Otro escenario de comprobación de estado muestra cómo filtrar las comprobaciones de estado por un puerto de administración. La aplicación de ejemplo requiere la creación de un archivo Properties/launchSettings.json que incluya la dirección URL de administración y el puerto de administración. Para obtener más información, consulte la sección Filtrado por puerto.

Sondeo de estado básico

Para muchas aplicaciones, una configuración de sondeo de estado básico que notifique la disponibilidad de la aplicación para procesar las solicitudes (ejecución) es suficiente para detectar el estado de la aplicación.

La configuración básica registra los servicios de comprobación de estado y llama al middleware de comprobaciones de estado para responder a un punto de conexión de dirección URL con una respuesta de estado. De forma predeterminada, no se registran comprobaciones de estado específicas para probar cualquier dependencia o subsistema concretos. La aplicación se considera en buen estado si puede responder en la dirección URL del punto de conexión de mantenimiento. El escritor de respuesta predeterminado escribe el estado (HealthStatus) como respuesta de texto no cifrado en el cliente, que indica un estado HealthStatus.Healthy, HealthStatus.Degraded o HealthStatus.Unhealthy.

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure.

En la aplicación de ejemplo, el punto de conexión de la comprobación de estado se crea en /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");
        });
    }
}

Para ejecutar el escenario de configuración básica mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario basic

Ejemplo de Docker

Docker ofrece una directiva de HEALTHCHECK integrada que puede utilizarse para comprobar el estado de una aplicación que use la configuración de comprobación de estado básica:

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

Creación de comprobaciones de estado

Las comprobaciones de estado se crean mediante la implementación de la interfaz de IHealthCheck. El método CheckHealthAsync devuelve un elemento HealthCheckResult que indica el estado como Healthy, Degraded o Unhealthy. El resultado se escribe como una respuesta de texto no cifrado con un código de estado configurable. (La configuración se describe en la sección Opciones de comprobación de estado). HealthCheckResult también puede devolver pares clave-valor opcionales.

La siguiente clase ExampleHealthCheck muestra el diseño de una comprobación de estado. La lógica de comprobaciones de estado se coloca en el método CheckHealthAsync. En el ejemplo siguiente se establece una variable ficticia, healthCheckResultHealthy, en true. Si el valor de healthCheckResultHealthy se establece en false, se devuelve el estado HealthCheckResult.Unhealthy.

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."));
    }
}

Registro de los servicios de comprobación de estado

El tipo ExampleHealthCheck se agrega a los servicios de comprobación de estado con AddCheck en Startup.ConfigureServices:

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

La sobrecarga AddCheck que se muestra en el ejemplo siguiente establece el estado de error (HealthStatus) para notificar cuándo la comprobación de estado informa de un error. Si el estado de error se establece en null (valor predeterminado), HealthStatus.Unhealthy se notifica. Esta sobrecarga es un escenario útil para los creadores de bibliotecas en los que la aplicación ejecuta el estado de error indicado por la biblioteca cuando se produce un error de comprobación de estado si la implementación de la comprobación de estado respeta la configuración.

Las etiquetas pueden usarse para filtrar las comprobaciones de estado, que se describen con más detalle en la sección Filtrado de las comprobaciones de estado.

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

AddCheck también puede ejecutar una función lambda. En el ejemplo siguiente, el nombre de la comprobación de estado se especifica como Example y la comprobación siempre devuelve un estado correcto:

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

Llame a AddTypeActivatedCheck para pasar argumentos a una implementación de comprobación de estado. En el ejemplo siguiente, TestHealthCheckWithArgs acepta un entero y una cadena que se van a usar cuando se llame a CheckHealthAsync:

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 se registra mediante un llamado a AddTypeActivatedCheck con el entero y la cadena que se pasaron a la implementación:

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

Uso del enrutamiento de comprobaciones de estado

En Startup.Configure, llame a MapHealthChecks en el generador de puntos de conexiones con la dirección URL del punto de conexión o la ruta de acceso relativa:

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

Requerimiento de host

Llame RequireHost a para especificar uno o más hosts permitidos para el punto de conexión de comprobación de estado. Los hosts deben ser Unicode en lugar de Punycode y pueden incluir un puerto. Si no se proporciona una colección, se acepta cualquier host.

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

Para obtener más información, consulte la sección Filtrado por puerto.

Requerimiento de autorización

Llame a RequireAuthorization para ejecutar el middleware de autorización en el punto de conexión de solicitudes de comprobación de estado. Una sobrecarga RequireAuthorization acepta una o varias directivas de autorización. Si no se proporciona una directiva, se usa la directiva de autorización predeterminada.

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

Habilitar solicitudes entre orígenes (CORS)

Aunque no se suelen ejecutar comprobaciones de estado manualmente desde un explorador, el middleware de CORS se puede habilitar mediante una llamada a RequireCors en los puntos de conexión de las comprobaciones de estado. Una sobrecarga RequireCors acepta un delegado del generador de directivas CORS (CorsPolicyBuilder) o un nombre de directiva. Si no se proporciona una directiva, se usa la directiva CORS predeterminada. Para obtener más información, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core.

Opciones de comprobación de estado

El elemento HealthCheckOptions ofrece una oportunidad para personalizar el comportamiento de las comprobaciones de estado:

Filtrado de las comprobaciones de estado

De forma predeterminada, el middleware de comprobaciones de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que devuelva un valor booleano para la opción Predicate. En el ejemplo siguiente, la etiqueta (bar_tag) de la comprobación de estado Bar la filtra, en la instrucción condicional de la función, donde true solo se devuelve si la propiedad Tags de la comprobación de estado coincide con foo_tag o baz_tag:

En 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" });

En Startup.Configure, el Predicate filtra la comprobación de estado "Bar". Solo se ejecutan Foo y Baz:

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

Personalización del código de estado HTTP

Use ResultStatusCodes para personalizar la asignación del estado de mantenimiento de los códigos de estado HTTP. Las siguientes asignaciones de StatusCodes son los valores predeterminados que el middleware utiliza. Cambie los valores de código de estado para satisfacer sus necesidades.

En Startup.Configure:

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

Supresión de los encabezados de caché

AllowCachingResponses controla si el middleware de comprobaciones de estado agrega encabezados HTTP a una respuesta de sondeo para evitar el almacenamiento en caché de respuesta. Si el valor es false (valor predeterminado), el middleware establece o invalida los encabezados Cache-Control, Expires y Pragma para evitar el almacenamiento en caché de respuesta. Si el valor es true, el middleware no modifica los encabezados de caché de la respuesta.

En Startup.Configure:

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

Personalización del resultado

En Startup.Configure, establezca la opción HealthCheckOptions.ResponseWriter en un delegado para escribir la respuesta:

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

El delegado predeterminado escribe una respuesta de texto no cifrado mínima con el valor de cadena HealthReport.Status. Los siguientes delegados personalizados generan una respuesta JSON personalizada.

En el primer ejemplo de la aplicación de ejemplo se muestra cómo usar 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);
    }
}

En el segundo ejemplo se muestra cómo usar 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));
}

En la aplicación de ejemplo, convierta en comentario la SYSTEM_TEXT_JSONdirectiva de preprocesador en CustomWriterStartup.csCustomWriterStartup.cs para habilitar la versión Newtonsoft.Json de WriteResponse.

La API de comprobaciones de estado no ofrece compatibilidad integrada con formatos de retorno JSON complejos porque el formato es específico del sistema de supervisión elegido. Personalice la respuesta en los ejemplos anteriores según sea necesario. Para más información sobre la serialización de JSON con System.Text.Json, consulte Procedimiento para serializar y deserializar JSON en .NET.

Sondeo de bases de datos

Una comprobación de estado puede especificar que una consulta de base de datos se ejecute como una prueba booleana para indicar si esta responde con normalidad.

En la aplicación de ejemplo se usa AspNetCore.Diagnostics.HealthChecks, una biblioteca de comprobaciones de estado para las aplicaciones de ASP.NET Core, a fin de ejecutar una comprobación de estado en una base de datos de SQL Server. AspNetCore.Diagnostics.HealthChecks ejecuta una consulta SELECT 1 en la base de datos para confirmar que la conexión a la base de datos es correcta.

Advertencia

Al comprobar la conexión de una base de datos a una consulta, elija una consulta que se devuelva rápidamente. El enfoque de la consulta plantea el riesgo de sobrecargar la base de datos y degradar el rendimiento. En la mayoría de los casos, no es necesario ejecutar una consulta de prueba. Simplemente, realizar una conexión correcta a la base de datos es suficiente. Si resulta necesario ejecutar una consulta, elija una consulta SELECT sencilla, como SELECT 1.

Incluya una referencia de paquete a AspNetCore.HealthChecks.SqlServer.

Proporcione una cadena de conexión a base de datos válida en el archivo appsettings.json de la aplicación de ejemplo. La aplicación usa una base de datos de SQL Server denominada 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": "*"
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. La aplicación de ejemplo llama al método AddSqlServer con la cadena de conexión de la base de datos (DbHealthStartup.cs):

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure:

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

Para ejecutar el escenario de sondeo de base de datos mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario db

Nota

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Sondeo de DbContext de Entity Framework Core

La comprobación DbContext confirma que la aplicación puede comunicarse con la base de datos configurada para un elemento DbContext de EF Core. La comprobación DbContext se admite en las aplicaciones que:

AddDbContextCheck<TContext> registra una comprobación de estado para un elemento DbContext. El elemento DbContext se proporciona como TContext en el método. Hay disponible una sobrecarga para configurar el estado de error, las etiquetas y una consulta de prueba personalizada.

De manera predeterminada:

  • DbContextHealthCheck llama al método CanConnectAsync de EF Core. Se puede personalizar qué operación se ejecuta al comprobar el estado con sobrecargas del método AddDbContextCheck.
  • El nombre de la comprobación de estado es el nombre del tipo TContext.

En la aplicación de ejemplo, se proporciona AppDbContext para AddDbContextCheck y se registra como un servicio en Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure:

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

Para ejecutar el escenario de sondeo de DbContext mediante la aplicación de ejemplo, confirme que la base de datos que la cadena de conexión especifica no exista en la instancia de SQL Server. Si la base de datos existe, elimínela.

Ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario dbcontext

Cuando la aplicación ya se esté ejecutando, compruebe el estado de mantenimiento mediante una solicitud al punto de conexión /health en un explorador. La base de datos y AppDbContext no existen, por lo que la aplicación proporciona la respuesta siguiente:

Unhealthy

Active la aplicación de ejemplo para crear la base de datos. Realice una solicitud a /createdatabase. La aplicación responde:

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

Realice una solicitud al punto de conexión /health. La base de datos y el contexto existen, por lo que la aplicación responde:

Healthy

Active la aplicación de ejemplo para eliminar la base de datos. Realice una solicitud a /deletedatabase. La aplicación responde:

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

Realice una solicitud al punto de conexión /health. La aplicación proporciona una respuesta incorrecta:

Unhealthy

Sondeos de preparación y ejecución independientes

En algunos escenarios de hospedaje, se usa un par de comprobaciones de estado que distinguen dos estados de la aplicación:

  • Preparación indica si la aplicación se ejecuta con normalidad, pero no está lista para recibir solicitudes.
  • Ejecución indica si una aplicación se ha bloqueado y debe reiniciarse.

Considere el ejemplo siguiente: Antes de estar lista para procesar solicitudes, una aplicación debe descargar un archivo de configuración de gran tamaño. No queremos que se reinicie la aplicación si se produce un error en la descarga inicial, dado que la aplicación puede volver a intentar descargar el archivo varias veces. Usamos un sondeo de ejecución para describir la ejecución del proceso, sin realizar ninguna otra comprobación. También queremos evitar que las solicitudes se envíen a la aplicación antes de que finalice la descarga del archivo de configuración. Hasta que no finaliza la descarga y la aplicación está lista para recibir solicitudes, usamos un sondeo de preparación para indicar un estado "no preparado".

La aplicación de ejemplo contiene una comprobación de estado para notificar la finalización de la tarea de inicio de ejecución prolongada en un servicio hospedado. El elemento StartupHostedServiceHealthCheck expone una propiedad, StartupTaskCompleted, que el servicio hospedado puede establecer en true al terminar su tarea de ejecución prolongada (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."));
    }
}

Un servicio hospedado (Services/StartupHostedService) se encarga de iniciar la tarea en segundo plano de larga ejecución. Al finalizar la tarea, StartupHostedServiceHealthCheck.StartupTaskCompleted se establece en 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()
    {
    }
}

La comprobación de estado se registra con AddCheck en Startup.ConfigureServices junto con el servicio hospedado. Dado que el servicio hospedado debe establecer la propiedad en la comprobación de estado, esta también se registra en el contenedor de servicios (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>();

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure. En la aplicación de ejemplo, los puntos de conexión de la comprobación de estado se crean en:

  • /health/ready para la comprobación de la idoneidad. La comprobación de preparación filtra las comprobaciones de estado con la etiqueta ready.
  • /health/live para la comprobación de la ejecución. La comprobación de ejecución filtra el elemento StartupHostedServiceHealthCheck devolviendo false en HealthCheckOptions.Predicate (para obtener más información, vea Filtrado de las comprobaciones de estado).

En el código de ejemplo siguiente:

  • La comprobación de preparación usa todas las comprobaciones registradas con la etiqueta "ready".
  • Predicate excluye todas las comprobaciones y devuelve una respuesta de que todo está correcto (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
    });
}

Para ejecutar el escenario de configuración de la preparación/ejecución mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario liveness

En un explorador, visite /health/ready varias veces hasta que hayan pasado 15 segundos. La comprobación de estado notifica un estado Unhealthy durante los primeros 15 segundos. Pasados 15 segundos, el punto de conexión notifica un estado Healthy, lo que indica que el servicio hospedado ya ha finalizado la tarea de ejecución prolongada.

En este ejemplo también se crea un publicador de la comprobación de estado (implementación IHealthCheckPublisher) que ejecuta la primera comprobación de preparación con un retraso de dos segundos. Para obtener más información, consulte la sección Publicador de la comprobación de estado.

Ejemplo de Kubernetes

Utilizar comprobaciones de preparación y ejecución independientes es útil en un entorno como Kubernetes. En Kubernetes, es posible que se requiera una aplicación para ejecutar un trabajo de inicio lento antes de aceptar solicitudes, como una prueba de la disponibilidad de la base de datos subyacente. El hecho de utilizar comprobaciones independientes permite que el orquestador distinga si la aplicación está funcionando, pero aún no esté preparada, o si la aplicación no se ha podido iniciar. Para obtener más información sobre los sondeos de preparación y ejecución en Kubernetes, consulte Configuración de sondeos de preparación y ejecución en la documentación de Kubernetes.

En el ejemplo siguiente, se muestra una configuración de sondeo de preparación de 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

Sondeo basado en métrica con un escritor de respuesta personalizada

La aplicación de ejemplo muestra una comprobación de estado de memoria con un escritor de respuesta personalizada.

MemoryHealthCheck notifica un estado degradado si la aplicación usa más de un umbral de memoria determinado (1 GB en la aplicación de ejemplo). El elemento HealthCheckResult incluye información del recolector de elementos no utilizados (GC) de la aplicación (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));
    }
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. En lugar de pasar la comprobación de estado a AddCheck para habilitarla, MemoryHealthCheck se registra como servicio. Todos los servicios registrados de IHealthCheck están disponibles para los servicios de comprobación de estado y middleware. Se recomienda registrar los servicios de comprobación de estado como los servicios de Singleton.

En CustomWriterStartup.cs de la aplicación de ejemplo:

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

Se crea un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure. Se proporciona un delegado de WriteResponse a la propiedad ResponseWriter para generar una respuesta JSON personalizada al ejecutarse la comprobación de estado:

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

El delegado WriteResponse da a CompositeHealthCheckResult el formato de objeto JSON y suspende el resultado de JSON para la respuesta de comprobación de estado. Para más información, consulte la sección Personalización del resultado.

Para ejecutar el sondeo basado en métrica con el resultado de un escritor de respuesta personalizada mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario writer

Nota

AspNetCore.Diagnostics.HealthChecks incluye escenarios de comprobación de estado basados en métricas, como las comprobaciones del almacenamiento del disco y de ejecución de máximo valor.

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Filtrado por puerto

Llame a RequireHost en MapHealthChecks con un patrón de dirección URL que especifique un puerto para restringir las solicitudes de comprobación de estado al puerto especificado. Este enfoque se usa normalmente en un entorno de contenedor para exponer un puerto para los servicios de supervisión.

La aplicación de ejemplo configura el puerto con el proveedor de configuración de variable de entorno. El puerto se establece en el archivo launchSettings.json y se pasa al proveedor de configuración a través de una variable de entorno. También debe configurar el servidor para que escuche las solicitudes en el puerto de administración.

Para utilizar la aplicación de ejemplo para que muestre la configuración del puerto de administración, cree el archivo launchSettings.json en una carpeta Properties.

El archivo Properties/launchSettings.json siguiente de la aplicación de ejemplo no se incluye en los archivos de proyecto de la aplicación de ejemplo y se debe crear manualmente:

{
  "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/"
    }
  }
}

Registre los servicios de comprobación de estado con AddHealthChecks de Startup.ConfigureServices. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks en Startup.Configure.

En la aplicación de ejemplo, una llamada a RequireHost en el punto de conexión Startup.Configure especifica el puerto de administración de la configuración:

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

Los puntos de conexión se crean en la aplicación de ejemplo en Startup.Configure. En el código de ejemplo siguiente:

  • La comprobación de preparación usa todas las comprobaciones registradas con la etiqueta "ready".
  • Predicate excluye todas las comprobaciones y devuelve una respuesta de que todo está correcto (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
    });
}

Nota

Para evitar la creación del archivo launchSettings.json en la aplicación de ejemplo, configure el puerto de administración explícitamente en código. En Program.cs, donde se crea HostBuilder, agregue una llamada a ListenAnyIP y proporcione el punto de conexión del puerto de administración de la aplicación. En Configure de ManagementPortStartup.cs, especifique el puerto de administración con 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");
});

Para ejecutar el escenario de configuración del puerto de administración mediante la aplicación de ejemplo, ejecute el comando siguiente desde la carpeta del proyecto en un shell de comandos:

dotnet run --scenario port

Distribución de una biblioteca de comprobación de estado

Para distribuir una comprobación de estado como una biblioteca, haga lo siguiente:

  1. Escriba una comprobación de estado que implemente la interfaz de IHealthCheck como una clase independiente. La clase puede depender de la inserción de dependencias (DI), de la activación del tipo y de las opciones denominadas para acceder a los datos de configuración.

    En la lógica de comprobaciones de estado de CheckHealthAsync:

    • data1 y data2 se usan en el método para ejecutar la lógica de comprobación de estado del sondeo.
    • Se controla AccessViolationException.

    Cuando se produce un AccessViolationException, se devuelve FailureStatus con HealthCheckResult para permitir que los usuarios configuren el estado de error de las comprobaciones de estado.

    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. Escriba un método de extensión con los parámetros a los que la aplicación de uso llama en su método Startup.Configure. En el ejemplo siguiente, suponga que existe la siguiente firma del método de comprobación de estado:

    ExampleHealthCheck(string, string, int )
    

    La firma anterior indica que la ExampleHealthCheck requiere datos adicionales para procesar la lógica de sondeo de la comprobación de estado. Los datos se proporcionan al delegado que se usa para crear la instancia de la comprobación de estado cuando la comprobación de estado se registra con un método de extensión. En el ejemplo siguiente, el autor de llamada especifica los siguientes elementos opcionales:

    • nombre de la comprobación de estado (name). En el caso de null, se utiliza example_health_check.
    • punto de datos de cadena para la comprobación de estado (data1).
    • punto de datos enteros para la comprobación de estado (data2). En el caso de null, se utiliza 1.
    • estado de error (HealthStatus). De manera predeterminada, es null. Si se utiliza null, HealthStatus.Unhealthy se notifica para un estado de error.
    • etiquetas (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));
        }
    }
    

Publicador de la comprobación de estado

Cuando un elemento IHealthCheckPublisher se agrega al contenedor de servicios, el sistema de comprobación de estado ejecuta periódicamente las comprobaciones de estado y llama a PublishAsync con el resultado. Esto es útil en un escenario de sistema de seguimiento de estado basado en inserción en el que se espera que cada proceso llame periódicamente al sistema de seguimiento con el fin de determinar el estado.

La interfaz de IHealthCheckPublisher tiene un único método:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions le permiten establecer:

  • Delay: el retraso inicial aplicado tras iniciarse la aplicación antes de ejecutar instancias de IHealthCheckPublisher. El retraso se aplica una vez durante el inicio y no se aplica a las iteraciones posteriores. El valor predeterminado es cinco segundos.
  • Period: el período de ejecución de IHealthCheckPublisher. El valor predeterminado es 30 segundos.
  • Predicate: si Predicate es null (valor predeterminado), el servicio de publicador de la comprobación de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que filtre el conjunto de comprobaciones. El predicado se evalúa cada período.
  • Timeout: el tiempo de expiración para ejecutar las comprobaciones de estado para todas las instancias de IHealthCheckPublisher. Use InfiniteTimeSpan para ejecutar sin tiempo de expiración. El valor predeterminado es 30 segundos.

En la aplicación de ejemplo, ReadinessPublisher es una implementación de IHealthCheckPublisher. El estado de comprobación de estado se registra para cada comprobación en un nivel de registro de:

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;
    }
}

En el ejemplo LivenessProbeStartup de la aplicación de ejemplo, la comprobación de preparación StartupHostedService tiene un retraso de inicio de dos segundos y ejecuta la comprobación cada 30 segundos. Para activar la implementación de IHealthCheckPublisher, el ejemplo registra ReadinessPublisher como servicio singleton en el contenedor de inserción de dependencias (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>();

Nota:

AspNetCore.Diagnostics.HealthChecks incluye editores para varios sistemas, incluido Application Insights.

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Restricción de las comprobaciones de estado con MapWhen

Use MapWhen para crear de forma condicional una rama de la canalización de solicitudes para los puntos de conexión de comprobación del estado.

En el ejemplo siguiente, MapWhen crea una rama de la canalización de solicitudes para activar el middleware de comprobaciones de estado si se recibe una solicitud GET para el punto de conexión 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();
});

Para obtener más información, consulte Middleware de ASP.NET Core.

ASP.NET Core ofrece el middleware de comprobaciones de estado y bibliotecas para informar sobre el estado de los componentes de la infraestructura de la aplicación.

Una aplicación se encarga de exponer las comprobaciones de estado como puntos de conexión HTTP. Los puntos de conexión de las comprobaciones de estado pueden configurarse para diversos escenarios de supervisión en tiempo real:

  • Los orquestadores de contenedores y los equilibradores de carga pueden utilizar los sondeos de estado para comprobar el estado de una aplicación. Por ejemplo, para responder a una comprobación de estado con errores, es posible que un orquestador de contenedores detenga una implementación en curso o reinicie un contenedor. Como respuesta a una aplicación con estado incorrecto, es posible que un equilibrador de carga enrute el tráfico al margen de la instancia con errores hacia una instancia con estado correcto.
  • El uso de la memoria, el disco y otros recursos del servidor físico puede supervisarse para determinar si el estado es correcto.
  • Las comprobaciones de estado pueden probar las dependencias de una aplicación, como las bases de datos y los puntos de conexión de servicio externo, para confirmar la disponibilidad y el funcionamiento normal.

Normalmente, las comprobaciones de estado se usan con un servicio de supervisión externa o un orquestador de contenedores para comprobar el estado de una aplicación. Antes de agregar comprobaciones de estado a una aplicación, debe decidir en qué sistema de supervisión se va a usar. El sistema de supervisión determina qué tipos de comprobaciones de estado se deben crear y cómo configurar sus puntos de conexión.

Sondeo de estado básico

Para muchas aplicaciones, una configuración de sondeo de estado básico que notifique la disponibilidad de la aplicación para procesar las solicitudes (ejecución) es suficiente para detectar el estado de la aplicación.

La configuración básica registra los servicios de comprobación de estado y llama al middleware de comprobaciones de estado para responder a un punto de conexión de dirección URL con una respuesta de estado. De forma predeterminada, no se registran comprobaciones de estado específicas para probar cualquier dependencia o subsistema concretos. La aplicación se considera en buen estado si puede responder en la dirección URL del punto de conexión de mantenimiento. El escritor de respuestas predeterminado escribe HealthStatus como una respuesta de texto no cifrado en el cliente. HealthStatus es HealthStatus.Healthy, HealthStatus.Degraded o HealthStatus.Unhealthy.

Registre los servicios de comprobación de estado con AddHealthChecks de Program.cs. Cree un punto de conexión de comprobación de estado llamando a MapHealthChecks.

En el ejemplo siguiente se crea un punto de conexión de comprobación de estado en /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker ofrece una directiva de HEALTHCHECK integrada que puede utilizarse para comprobar el estado de una aplicación que use la configuración de comprobación de estado básica:

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

El ejemplo anterior utiliza curl para hacer una solicitud HTTP al punto de conexión de comprobación de estado en /healthz. curl no se incluye en las imágenes de contenedor de Linux de .NET, pero se puede agregar instalando el paquete necesario en Dockerfile. Los contenedores que usan imágenes basadas en Alpine Linux pueden usar el wget incluido en lugar de curl.

Creación de comprobaciones de estado

Las comprobaciones de estado se crean mediante la implementación de la interfaz de IHealthCheck. El método CheckHealthAsync devuelve un elemento HealthCheckResult que indica el estado como Healthy, Degraded o Unhealthy. El resultado se escribe como una respuesta de texto no cifrado con un código de estado configurable. La configuración se describe en la sección Opciones de comprobación de estado. HealthCheckResult también puede devolver pares clave-valor opcionales.

En el ejemplo siguiente se muestra el diseño de una comprobación de estado:

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 lógica de comprobaciones de estado se coloca en el método CheckHealthAsync. En el ejemplo siguiente se establece una variable ficticia, isHealthy, en true. Si el valor de isHealthy se establece en false, se devuelve el estado HealthCheckRegistration.FailureStatus.

Si CheckHealthAsync produce una excepción durante la comprobación, se devuelve un nuevo HealthReportEntry con su HealthReportEntry.Status establecido en FailureStatus. Este estado se define mediante AddCheck (consulte la sección Registro de los servicios de comprobación de estado) e incluye la excepción interna que produjo el error de comprobación. Description se establece en el mensaje de la excepción.

Registro de los servicios de comprobación de estado

Para registrar un servicio de comprobación de estado, llame a AddCheck en Program.cs:

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

La sobrecarga AddCheck que se muestra en el ejemplo siguiente establece el estado de error (HealthStatus) para notificar cuándo la comprobación de estado informa de un error. Si el estado de error se establece en null (valor predeterminado), HealthStatus.Unhealthy se notifica. Esta sobrecarga es un escenario útil para los creadores de bibliotecas en los que la aplicación ejecuta el estado de error indicado por la biblioteca cuando se produce un error de comprobación de estado si la implementación de la comprobación de estado respeta la configuración.

Las etiquetas se pueden usar para filtrar las comprobaciones de estado. Las etiquetas se describen en la sección Filtrado de comprobaciones de estado.

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

AddCheck también puede ejecutar una función lambda. En el ejemplo siguiente, la comprobación de estado siempre devuelve un resultado correcto:

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

Llame a AddTypeActivatedCheck para pasar argumentos a una implementación de comprobación de estado. En el ejemplo siguiente, una comprobación de estado activada por tipo acepta un entero y una cadena en su constructor:

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."));
    }
}

Para registrar la comprobación de estado anterior, llame a AddTypeActivatedCheck con el entero y la cadena pasados como argumentos:

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

Uso del enrutamiento de comprobaciones de estado

En Program.cs, llame a MapHealthChecks en el generador de puntos de conexiones con la dirección URL del punto de conexión o la ruta de acceso relativa:

app.MapHealthChecks("/healthz");

Requerimiento de host

Llame RequireHost a para especificar uno o más hosts permitidos para el punto de conexión de comprobación de estado. Los hosts deben ser Unicode en lugar de Punycode y pueden incluir un puerto. Si no se proporciona una colección, se acepta cualquier host:

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

Para restringir el punto de conexión de comprobación de estado para que responda solo en un puerto específico, especifique un puerto en la llamada a RequireHost. Este enfoque se usa normalmente en un entorno de contenedor para exponer un puerto para los servicios de supervisión:

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

Advertencia

Las API que se basan en el encabezado host, como HttpRequest.Host y RequireHost, están sujetas a una posible suplantación de identidad por parte de los clientes.

Para evitar la suplantación de identidad de host y puerto, use uno de los métodos siguientes:

Para evitar que los clientes no autorizados suplanten el puerto, llame a RequireAuthorization:

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

Para obtener más información, consulte Comparación de host en rutas con RequireHost.

Requerimiento de autorización

Llame a RequireAuthorization para ejecutar el middleware de autorización en el punto de conexión de solicitudes de comprobación de estado. Una sobrecarga RequireAuthorization acepta una o varias directivas de autorización. Si no se proporciona una directiva, se usa la directiva de autorización predeterminada:

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

Habilitar solicitudes entre orígenes (CORS)

Aunque no se suelen ejecutar comprobaciones de estado manualmente desde un explorador, el middleware de CORS se puede habilitar mediante una llamada a RequireCors en los puntos de conexión de las comprobaciones de estado. La sobrecarga de RequireCors acepta un delegado del generador de directivas CORS (CorsPolicyBuilder) o un nombre de directiva. Para obtener más información, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core.

Opciones de comprobación de estado

El elemento HealthCheckOptions ofrece una oportunidad para personalizar el comportamiento de las comprobaciones de estado:

Filtrado de las comprobaciones de estado

De forma predeterminada, el middleware de comprobaciones de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que devuelva un valor booleano para la opción Predicate.

En el ejemplo siguiente se filtran las comprobaciones de estado para que solo se ejecuten aquellas etiquetadas con sample:

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

Personalización del código de estado HTTP

Use ResultStatusCodes para personalizar la asignación del estado de mantenimiento de los códigos de estado HTTP. Las siguientes asignaciones de StatusCodes son los valores predeterminados que el middleware utiliza. Cambie los valores de código de estado para satisfacer sus necesidades:

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

Supresión de los encabezados de caché

AllowCachingResponses controla si el middleware de comprobaciones de estado agrega encabezados HTTP a una respuesta de sondeo para evitar el almacenamiento en caché de respuesta. Si el valor es false (valor predeterminado), el middleware establece o invalida los encabezados Cache-Control, Expires y Pragma para evitar el almacenamiento en caché de respuesta. Si el valor es true, el middleware no modifica los encabezados de caché de la respuesta:

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

Personalización del resultado

Para personalizar la salida de un informe de comprobaciones de estado, establezca la propiedad HealthCheckOptions.ResponseWriter en un delegado que escriba la respuesta:

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

El delegado predeterminado escribe una respuesta de texto no cifrado mínima con el valor de cadena HealthReport.Status. El siguiente delegado personalizado genera una respuesta JSON personalizada mediante 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()));
}

La API de comprobaciones de estado no ofrece compatibilidad integrada con formatos de retorno JSON complejos porque el formato es específico del sistema de supervisión elegido. Personalice la respuesta en los ejemplos anteriores según sea necesario. Para más información sobre la serialización de JSON con System.Text.Json, consulte Procedimiento para serializar y deserializar JSON en .NET.

Sondeo de bases de datos

Una comprobación de estado puede especificar que una consulta de base de datos se ejecute como una prueba booleana para indicar si esta responde con normalidad.

AspNetCore.Diagnostics.HealthChecks, una biblioteca de comprobación de estado para aplicaciones ASP.NET Core, incluye una comprobación de estado que se ejecuta en una base de datos SQL Server. AspNetCore.Diagnostics.HealthChecks ejecuta una consulta SELECT 1 en la base de datos para confirmar que la conexión a la base de datos es correcta.

Advertencia

Al comprobar la conexión de una base de datos a una consulta, elija una consulta que se devuelva rápidamente. El enfoque de la consulta plantea el riesgo de sobrecargar la base de datos y degradar el rendimiento. En la mayoría de los casos, no es necesario ejecutar una consulta de prueba. Simplemente, realizar una conexión correcta a la base de datos es suficiente. Si resulta necesario ejecutar una consulta, elija una consulta SELECT sencilla, como SELECT 1.

Para utilizar esta comprobación de estado de SQL Server, incluya una referencia al paquete NuGet AspNetCore.HealthChecks.SqlServer. En el ejemplo siguiente se registra la comprobación de estado de SQL Server:

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

Nota

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Sondeo de DbContext de Entity Framework Core

La comprobación DbContext confirma que la aplicación puede comunicarse con la base de datos configurada para un elemento DbContext de EF Core. La comprobación DbContext se admite en las aplicaciones que:

AddDbContextCheck registra una comprobación de estado para un elemento DbContext. El elemento DbContext se proporciona al método como TContext. Hay disponible una sobrecarga para configurar el estado de error, las etiquetas y una consulta de prueba personalizada.

De manera predeterminada:

  • DbContextHealthCheck llama al método CanConnectAsync de EF Core. Se puede personalizar qué operación se ejecuta al comprobar el estado con sobrecargas del método AddDbContextCheck.
  • El nombre de la comprobación de estado es el nombre del tipo TContext.

En el siguiente ejemplo se registra DbContext y un DbContextHealthCheck asociado:

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

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

Sondeos de preparación y ejecución independientes

En algunos escenarios de hospedaje, se usa un par de comprobaciones de estado que distinguen dos estados de la aplicación:

  • Preparación indica si la aplicación se ejecuta con normalidad, pero no está lista para recibir solicitudes.
  • Ejecución indica si una aplicación se ha bloqueado y debe reiniciarse.

Considere el ejemplo siguiente: Antes de estar lista para procesar solicitudes, una aplicación debe descargar un archivo de configuración de gran tamaño. No queremos que se reinicie la aplicación si se produce un error en la descarga inicial, dado que la aplicación puede volver a intentar descargar el archivo varias veces. Usamos un sondeo de ejecución para describir la ejecución del proceso, sin realizar ninguna otra comprobación. También queremos evitar que las solicitudes se envíen a la aplicación antes de que finalice la descarga del archivo de configuración. Hasta que no finaliza la descarga y la aplicación está lista para recibir solicitudes, usamos un sondeo de preparación para indicar un estado "no preparado".

La siguiente tarea en segundo plano simula un proceso de inicio que tarda aproximadamente 15 segundos. Una vez que se completa, la tarea establece la propiedad StartupHealthCheck.StartupCompleted en true:

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;
    }
}

StartupHealthCheck notifica la finalización de la tarea de inicio de ejecución prolongada y expone la propiedad StartupCompleted establecida por el servicio en segundo plano:

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."));
    }
}

La comprobación de estado se registra con AddCheck en Program.cs junto con el servicio hospedado. Dado que el servicio hospedado debe establecer la propiedad en la comprobación de estado, esta también se registra en el contenedor de servicios como singleton:

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

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

Para crear dos puntos de conexión de comprobación de estado diferentes, llame a MapHealthChecks dos veces:

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

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

En el ejemplo anterior se crean los siguientes puntos de conexión de comprobación de estado:

  • /healthz/ready para la comprobación de la idoneidad. La comprobación de preparación filtra las comprobaciones de estado a las etiquetadas con ready.
  • /healthz/live para la comprobación de la ejecución. La comprobación de ejecución filtra todas las comprobaciones de estado devolviendo false en el delegado HealthCheckOptions.Predicate. Para obtener más información sobre el filtrado de comprobaciones de estado, vea Filtrado de las comprobaciones de estado en este artículo.

Antes de que se complete la tarea de inicio, el punto de conexión /healthz/ready notifica un estado Unhealthy. Después de que se complete la tarea de inicio, este punto de conexión notifica un estado Healthy. El punto de conexión /healthz/live excluye todas las comprobaciones e informa de un estado Healthy para todas las llamadas.

Ejemplo de Kubernetes

Utilizar comprobaciones de preparación y ejecución independientes es útil en un entorno como Kubernetes. En Kubernetes, es posible que se requiera una aplicación para ejecutar un trabajo de inicio lento antes de aceptar solicitudes, como una prueba de la disponibilidad de la base de datos subyacente. El hecho de utilizar comprobaciones independientes permite que el orquestador distinga si la aplicación está funcionando, pero aún no esté preparada, o si la aplicación no se ha podido iniciar. Para obtener más información sobre los sondeos de preparación y ejecución en Kubernetes, consulte Configuración de sondeos de preparación y ejecución en la documentación de Kubernetes.

En el ejemplo siguiente, se muestra una configuración de sondeo de preparación de 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

Distribución de una biblioteca de comprobación de estado

Para distribuir una comprobación de estado como una biblioteca, haga lo siguiente:

  1. Escriba una comprobación de estado que implemente la interfaz de IHealthCheck como una clase independiente. La clase puede depender de la inserción de dependencias (DI), de la activación del tipo y de las opciones denominadas para acceder a los datos de configuración.

  2. Escriba un método de extensión con los parámetros a los que la aplicación de uso llama en su método Program.cs. Considere la siguiente comprobación de estado de ejemplo, que acepta arg1 y arg2 como parámetros de constructor:

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

    La firma anterior indica que la comprobación de estado requiere datos personalizados para procesar la lógica de sondeo de la comprobación de estado. Los datos se proporcionan al delegado que se usa para crear la instancia de la comprobación de estado cuando la comprobación de estado se registra con un método de extensión. En el ejemplo siguiente, el autor de la llamada especifica:

    • arg1: punto de datos de entero para la comprobación de estado.
    • arg2: argumento de cadena para la comprobación de estado.
    • name: nombre de comprobación de estado opcional. Si null, se usa el valor predeterminado.
    • failureStatus: un HealthStatus opcional, que se notifica para un estado de error. En el caso de null, se utiliza HealthStatus.Unhealthy.
    • tags: una colección IEnumerable<string> opcional de etiquetas.
    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));
        }
    }
    

Publicador de la comprobación de estado

Cuando un elemento IHealthCheckPublisher se agrega al contenedor de servicios, el sistema de comprobación de estado ejecuta periódicamente las comprobaciones de estado y llama a PublishAsync con el resultado. Este proceso es útil en un escenario de sistema de supervisión de estado basado en inserción que espera que cada proceso llame periódicamente al sistema de supervisión para determinar el estado.

HealthCheckPublisherOptions le permiten establecer:

  • Delay: el retraso inicial aplicado tras iniciarse la aplicación antes de ejecutar instancias de IHealthCheckPublisher. El retraso se aplica una vez en el inicio y no se aplica a iteraciones posteriores. El valor predeterminado es cinco segundos.
  • Period: el período de ejecución de IHealthCheckPublisher. El valor predeterminado es 30 segundos.
  • Predicate: si Predicate es null (valor predeterminado), el servicio de publicador de la comprobación de estado ejecuta todas las comprobaciones de estado registradas. Para ejecutar un subconjunto de comprobaciones de estado, proporcione una función que filtre el conjunto de comprobaciones. El predicado se evalúa cada período.
  • Timeout: el tiempo de expiración para ejecutar las comprobaciones de estado para todas las instancias de IHealthCheckPublisher. Use InfiniteTimeSpan para ejecutar sin tiempo de expiración. El valor predeterminado es 30 segundos.

En el ejemplo siguiente se muestra el diseño de un publicador de estado:

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

        return Task.CompletedTask;
    }
}

La clase HealthCheckPublisherOptions proporciona propiedades para configurar el comportamiento del publicador de la comprobación de estado.

En el ejemplo siguiente se registra un publicador de comprobación de estado como singleton y se configura HealthCheckPublisherOptions:

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

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

Nota

AspNetCore.Diagnostics.HealthChecks incluye editores para varios sistemas, incluido Application Insights.

Microsoft no mantiene ni admite AspNetCore.Diagnostics.HealthChecks.

Inserción de dependencias y comprobaciones de estado

Se puede usar la inserción de dependencias para consumir una instancia de un elemento Type específico dentro de una clase de comprobación de estado (Health Check). La inserción de dependencias puede ser útil para insertar opciones o una configuración global en una comprobación de estado. El uso de la inserción de dependencias no es un escenario común para configurar comprobaciones de estado. Normalmente, cada comprobación de estado es bastante específica para la prueba real y se configura mediante métodos de extensión IHealthChecksBuilder.

En el ejemplo siguiente se muestra una comprobación de estado de ejemplo que recupera un objeto de configuración a través de la inserción de dependencias:

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."));
    }
}

El elemento SampleHealthCheckWithDiConfig y la comprobación de estado deben agregarse al contenedor de servicios:

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 frente a MapHealthChecks

Hay dos maneras de que las comprobaciones de estado sean accesibles para los autores de llamadas:

  • UseHealthChecks registra el middleware para controlar las solicitudes de comprobaciones de estado en la canalización de middleware.
  • MapHealthChecks registra un punto de conexión de comprobaciones de estado. El punto de conexión coincide y se ejecuta junto con otros puntos de conexión de la aplicación.

La ventaja de usar MapHealthChecks sobre UseHealthChecks es la capacidad de usar middleware compatible con puntos de conexión, como la autorización, y tener un mayor control específico sobre la directiva de coincidencias. La principal ventaja de usar UseHealthChecks sobre MapHealthChecks es controlar exactamente dónde se ejecutan las comprobaciones de estado en la canalización de middleware.

UseHealthChecks:

  • Finaliza la canalización cuando una solicitud coincide con el punto de conexión de comprobación de estado. Un cortocircuito suele ser deseable porque evita el trabajo innecesario, como el registro y otro middleware.
  • Se usa principalmente para configurar el middleware de las comprobaciones de estado en la canalización.
  • Puede coincidir con cualquier ruta de acceso de un puerto con un null o PathString vacío. Permite realizar una comprobación de estado en cualquier solicitud realizada al puerto especificado.
  • Código fuente

MapHealthChecks permite:

  • Asignar rutas o puntos de conexión específicos para las comprobaciones de estado.
  • Personalización de la dirección URL o ruta de acceso a la que se puede acceder al punto de conexión de la comprobación de estado.
  • Asignación de varios puntos de conexión de la comprobación de estado con diferentes rutas o configuraciones. Compatibilidad con varios puntos de conexión:
    • Habilita puntos de conexión independientes para distintos tipos de comprobaciones de estado o componentes.
    • Se usa para diferenciar entre distintos aspectos del estado de la aplicación o aplicar configuraciones específicas a subconjuntos de comprobaciones de estado.
  • Código fuente

Recursos adicionales

Nota:

Este artículo se ha creado parcialmente con ayuda de inteligencia artificial. Antes de la publicación, un autor ha revisado y corregido el contenido según ha estimado necesario. Consulta Los principios para usar contenido generado por IA en Microsoft Learn.