Verificações de integridade no ASP.NET Core

Por Glenn Condron e Juergen Gutsch

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

O ASP.NET Core oferece o Middleware de Verificações de Integridade e bibliotecas para relatar a integridade de componentes de infraestrutura do aplicativo.

As verificações de integridade são expostas por um aplicativo como pontos de extremidade HTTP. Os pontos de extremidade de verificação de integridade podem ser configurados para vários cenários de monitoramento em tempo real:

  • As investigações de integridade podem ser usadas por orquestradores de contêineres e balanceadores de carga para verificar o status de um aplicativo. Por exemplo, um orquestrador de contêineres pode responder a uma verificação de integridade com falha interrompendo uma implantação sem interrupção ou reiniciando um contêiner. Um balanceador de carga pode reagir a um aplicativo não íntegro encaminhando o tráfego para fora da instância com falha para uma instância íntegra.
  • O uso de memória, disco e outros recursos de servidor físico pode ser monitorado quanto ao status de integridade.
  • As verificações de integridade podem testar as dependências do aplicativo, como bancos de dados e pontos de extremidade de serviço externo, para confirmar a disponibilidade e o funcionamento normal.

As verificações de integridade são normalmente usadas com um orquestrador de contêineres ou um serviço de monitoramento externo para verificar o status de um aplicativo. Antes de adicionar verificações de integridade a um aplicativo, decida qual sistema de monitoramento será usado. O sistema de monitoramento determina quais tipos de verificações de integridade serão criados e como configurar seus pontos de extremidade.

Investigação de integridade básica

Para muitos aplicativos, uma configuração básica de investigação de integridade que relata a disponibilidade do aplicativo para processar solicitações (atividade) é suficiente para descobrir o status do aplicativo.

A configuração básica registra os serviços de verificação de integridade e chama o Middleware de Verificações de Integridade para responder a um ponto de extremidade de URL com uma resposta de integridade. Por padrão, nenhuma verificação de integridade específica é registrada para testar qualquer dependência ou subsistema específico. O aplicativo é considerado íntegro se consegue responder na URL do ponto de extremidade de integridade. O gravador de resposta padrão grava HealthStatus como uma resposta de texto sem formatação para o cliente. O HealthStatus é HealthStatus.Healthy, HealthStatus.Degradedou HealthStatus.Unhealthy.

Registre os serviços de verificação de integridade com AddHealthChecks em Program.cs. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks.

O exemplo a seguir cria um ponto de extremidade de verificação de integridade em /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

O Docker oferece uma diretiva HEALTHCHECK interna que pode ser usada para verificar o status de um aplicativo que usa a configuração básica de verificação de integridade:

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

O exemplo anterior usa curl para fazer uma solicitação HTTP para o ponto de extremidade de verificação de integridade em /healthz. curl não está incluído nas imagens de contêiner do .NET Linux, mas pode ser adicionado instalando o pacote necessário no Dockerfile. Os contêineres que usam imagens com base no Alpine Linux podem usar o wget incluído ao invés de curl.

Criar verificações de integridade

As verificações de integridade são criadas pela implementação da interface IHealthCheck. O método CheckHealthAsync retorna um HealthCheckResult que indica a integridade como Healthy, Degraded ou Unhealthy. O resultado é gravado como uma resposta de texto sem formatação com um código de status configurável. A configuração é descrita na seção Opções de verificação de integridade. HealthCheckResult também pode retornar pares chave-valor opcionais.

O exemplo a seguir demonstra o layout de uma verificação de integridade:

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

A lógica da verificação de integridade é colocada no método CheckHealthAsync. O exemplo anterior define uma variável fictícia, isHealthy, como true. Se o valor de isHealthy for definido como false, o status de HealthCheckRegistration.FailureStatus será retornado.

Se CheckHealthAsync gerar uma exceção durante a verificação, um novo HealthReportEntry será retornado com seu HealthReportEntry.Status definido como FailureStatus. Esse status é definido por AddCheck (consulte a seção Registrar serviços de verificação de integridade) e inclui a exceção interna que causou a falha de verificação. O Description é definido como a mensagem da exceção.

Registrar os serviços de verificação de integridade

Para registrar um serviço de verificação de integridade, chame AddCheck em Program.cs:

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

A sobrecarga AddCheck mostrada no exemplo a seguir define o status de falha (HealthStatus) como relatório quando a verificação de integridade relata uma falha. Se o status de falha é definido como null (padrão), HealthStatus.Unhealthy é relatado. Essa sobrecarga é um cenário útil para autores de biblioteca, em que o status de falha indicado pela biblioteca é imposto pelo aplicativo quando uma falha de verificação de integridade ocorre se a implementação da verificação de integridade respeita a configuração.

Marcações podem ser usadas para filtrar verificações de integridade. As marcações são descritas na seção Filtrar verificações de integridade.

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

AddCheck também pode executar uma função lambda. No exemplo a seguir, a verificação de integridade sempre retorna um resultado íntegro:

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

Chame AddTypeActivatedCheck para aprovar argumentos para uma implementação de verificação de integridade. No exemplo a seguir, uma verificação de integridade ativada por tipo aceita um inteiro e uma cadeia de caracteres em seu construtor:

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 a verificação de integridade anterior, chame AddTypeActivatedCheck com o inteiro e a cadeia de caracteres aprovados como argumentos:

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

Usar roteamento de verificações de integridade

No Program.cs, chame MapHealthChecks no construtor de ponto de extremidade com a URL de ponto de extremidade ou o caminho relativo:

app.MapHealthChecks("/healthz");

Exigir host

Chame RequireHost para especificar um ou mais hosts permitidos para o ponto de extremidade de verificação de integridade. Os hosts devem ser Unicode em vez de punycode e podem incluir uma porta. Se uma coleção não for fornecida, qualquer host será aceito:

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

Para restringir o ponto de extremidade de verificação de integridade para responder somente em uma determinada porta, especifique uma porta na chamada para RequireHost. Essa abordagem normalmente é usada em um ambiente de contêiner para expor uma porta para os serviços de monitoramento:

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

Aviso

Uma API que dependa do cabeçalho de host, como HttpRequest.Host e RequireHost, está sujeita a possíveis falsificações por clientes.

Para evitar falsificação de host e porta, use uma das seguintes abordagens:

Para impedir que clientes não autorizados falsifiquem a porta, chame RequireAuthorization:

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

Para obter mais informações, consulte Correspondência de host em rotas com RequireHost.

Exigir autorização

Chame RequireAuthorization para executar o Middleware de autorização no ponto de extremidade da solicitação de verificação de integridade. Uma sobrecarga RequireAuthorization aceita uma ou mais políticas de autorização. Se uma política não for fornecida, a política de autorização padrão será usada:

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

Habilitar o CORS (Solicitações Entre Origens)

Embora a execução manual das verificações de integridade de um navegador não seja um cenário comum, o Middleware CORS pode ser habilitado chamando RequireCors nos pontos de extremidade das verificações de integridade. A sobrecarga RequireCors aceita um representante do construtor de políticas CORS (CorsPolicyBuilder) ou um nome de política. Para obter mais informações, consulte Habilitar solicitações entre origens (CORS, na sigla em inglês) no ASP.NET Core.

Opções de verificação de integridade

HealthCheckOptions oferece uma oportunidade de personalizar o comportamento de verificação de integridade:

Filtrar verificações de integridade

Por padrão, o Middleware de verificações de integridade executa todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que retorne um booliano para a opção Predicate.

O exemplo a seguir filtra as verificações de integridade para que somente aquelas marcadas com sample sejam executadas:

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

Personalizar o código de status HTTP

Use ResultStatusCodes para personalizar o mapeamento de status da integridade para códigos de status HTTP. As atribuições StatusCodes a seguir são os valores padrão usados pelo middleware. Altere os valores do código de status de acordo com suas necessidades:

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

Suprimir os cabeçalhos de cache

AllowCachingResponses controla se o Middleware de verificações de integridade adiciona cabeçalhos HTTP a uma resposta de investigação para prevenir o cache de resposta. Se o valor é false (padrão), o middleware define ou substitui os cabeçalhos Cache-Control, Expires e Pragma para prevenir o cache de resposta. Se o valor for true, o middleware não modifica os cabeçalhos de cache da resposta:

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

Personalizar a saída

Para personalizar a saída de um relatório de verificações de integridade, defina a propriedade HealthCheckOptions.ResponseWriter como um representante que grava a resposta:

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

O representante padrão grava uma resposta mínima de texto sem formatação com o valor de cadeia de caracteres HealthReport.Status. O representante personalizado a seguir gera uma JSresposta ON personalizada usando 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()));
}

A API de verificações de integridade não fornece suporte interno para formatos de retorno JSON complexos porque o formato é específico para sua escolha de sistema de monitoramento. Personalize a resposta nos exemplos anteriores, conforme necessário. Para obter mais informações sobre a serialização JSON com System.Text.Json, consulte Como serializar e desserializar JSON no .NET.

Investigação de banco de dados

Uma verificação de integridade pode especificar uma consulta de banco de dados a ser executada como um teste booliano para indicar se o banco de dados está respondendo normalmente.

AspNetCore.Diagnostics.HealthChecks, uma biblioteca de verificação de integridade para aplicativos do ASP.NET Core, inclui uma verificação de integridade executada em um banco de dados do SQL Server. O AspNetCore.Diagnostics.HealthChecks executa uma consulta SELECT 1 no banco de dados para confirmar se a conexão ao banco de dados está íntegra.

Aviso

Ao verificar uma conexão de banco de dados com uma consulta, escolha uma consulta que retorne rapidamente. A abordagem de consulta corre o risco de sobrecarregar o banco de dados e prejudicar o desempenho. Na maioria dos casos, a execução de uma consulta de teste não é necessária. É suficiente apenas estabelecer uma conexão bem-sucedida ao banco de dados. Se você achar necessário executar uma consulta, escolha uma consulta SELECT simples, como SELECT 1.

Para usar essa verificação de integridade do SQL Server, inclua uma referência de pacote ao pacote AspNetCore.HealthChecks.SqlServer NuGet. O exemplo a seguir registra a verificação de integridade do 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);

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Investigação de DbContext do Entity Framework Core

A verificação DbContext confirma se o aplicativo pode se comunicar com o banco de dados configurado para um EF CoreDbContext. A verificação DbContext é compatível em aplicativos que:

AddDbContextCheck registra uma verificação de integridade para um DbContext. O DbContext é fornecido ao método como o TContext. Uma sobrecarga está disponível para configurar o status de falha, marcas e uma consulta de teste personalizada.

Por padrão:

  • O DbContextHealthCheck chama o método CanConnectAsync do EF Core. Você pode personalizar qual operação é executada durante a verificação de integridade usando sobrecargas do método AddDbContextCheck.
  • O nome da verificação de integridade é o nome do tipo TContext.

O exemplo a seguir registra um DbContext e um DbContextHealthCheck associado:

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

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

Investigações de preparação e atividade separadas

Em alguns cenários de hospedagem, é usado um par de verificações de integridade que distingue dois estados de aplicativo:

  • Preparação indica se o aplicativo está em execução normalmente, mas não está pronto para receber solicitações.
  • Atividade indica se um aplicativo falhou e deve ser reiniciado.

Considere o exemplo a seguir: um aplicativo deve baixar um arquivo de configuração grande antes de estar pronto para processar solicitações. Não queremos que o aplicativo seja reiniciado se o download inicial falhar porque o aplicativo pode tentar baixar o arquivo novamente várias vezes. Usamos uma investigação de atividade para descrever a atividade do processo; nenhuma outra verificação é executada. Também queremos impedir que as solicitações sejam enviadas ao aplicativo antes que o download do arquivo de configuração seja bem-sucedido. Usamos uma investigação de preparação para indicar um estado "não pronto" até que o download seja bem-sucedido e o aplicativo esteja pronto para receber solicitações.

A tarefa em segundo plano a seguir simula um processo de inicialização que leva cerca de 15 segundos. Depois de concluída, a tarefa define a propriedade StartupHealthCheck.StartupCompleted como 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;
    }
}

O StartupHealthCheck relata a conclusão da tarefa de inicialização de execução prolongada e expõe a propriedade StartupCompleted que é definida pelo serviço em 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."));
    }
}

A verificação de integridade é registrada em AddCheck no Program.cs juntamente com o serviço hospedado. Como o serviço hospedado precisa definir a propriedade na verificação de integridade, a verificação de integridade também é registrada no contêiner de serviço como um banco de dados individual:

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

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

Para criar dois pontos de extremidade de verificação de integridade diferentes, chame MapHealthChecks duas vezes:

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

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

O exemplo anterior cria os seguintes pontos de extremidade de verificação de integridade:

  • /healthz/ready para a verificação de preparação. A verificação de preparação filtra as verificações de integridade para aquelas marcadas com ready.
  • /healthz/live para a verificação de atividade. A verificação de atividade filtra todas as verificações de integridade retornando false no representante HealthCheckOptions.Predicate. Para obter mais informações sobre como filtrar verificações de integridade, consulte Filtrar verificações de integridade neste artigo.

Antes da conclusão da tarefa de inicialização, o ponto de extremidade /healthz/ready relata um status Unhealthy. Depois que a tarefa de inicialização for concluída, esse ponto de extremidade relatará um status Healthy. O ponto de extremidade /healthz/live exclui todas as verificações e relata um status Healthy para todas as chamadas.

Exemplo do Kubernetes

O uso de verificações de preparação e atividade separadas é útil em um ambiente como o Kubernetes. No Kubernetes, um aplicativo pode precisar executar um trabalho de inicialização demorado antes de aceitar solicitações, como um teste da disponibilidade do banco de dados subjacente. O uso de verificações separadas permite que o orquestrador distinga se o aplicativo está funcionando, mas ainda não está pronto, ou se o aplicativo falhou ao ser iniciado. Para obter mais informações sobre as investigações de preparação e atividade no Kubernetes, confira Configurar investigações de preparação e atividade na documentação do Kubernetes.

O seguinte exemplo demonstra uma configuração de investigação de preparação do 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

Distribuir uma biblioteca de verificação de integridade

Para distribuir uma verificação de integridade como uma biblioteca:

  1. Escreva uma verificação de integridade que implementa a interface IHealthCheck como uma classe autônoma. A classe pode depender da DI (injeção de dependência), da ativação de tipo e das opções nomeadas para acessar os dados de configuração.

  2. Escreva um método de extensão com parâmetros que o aplicativo de consumo chama em seu método Program.cs. Considere o exemplo a seguir de verificação de integridade, que aceita arg1 e arg2 como parâmetros de construtor:

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

    A assinatura anterior indica que a verificação de integridade exige dados personalizados para processar a lógica de investigação da verificação de integridade. Os dados são fornecidos para o representante usado para criar a instância de verificação de integridade quando a verificação de integridade é registrada em um método de extensão. No exemplo a seguir, o chamador especifica:

    • arg1: um ponto de dados de inteiro para a verificação de integridade.
    • arg2: um argumento de cadeia de caracteres para a verificação de integridade.
    • name: um nome de verificação de integridade opcional. Se null, o valor padrão é usado.
    • failureStatus: um HealthStatus opcional, que é relatado para um status de falha. Se null, HealthStatus.Unhealthy é usado.
    • tags: uma coleção IEnumerable<string> opcional de marcações.
    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 Verificação de Integridade

Quando um IHealthCheckPublisher é adicionado ao contêiner de serviços, o sistema de verificação de integridade periodicamente executa sua verificação de integridade e chama PublishAsync com o resultado. Esse processo é útil em um cenário de sistema de monitoramento de integridade baseado em push que espera que cada processo chame o sistema de monitoramento periodicamente para determinar a integridade.

HealthCheckPublisherOptions permite que você defina:

  • Delay: o atraso inicial aplicado após o aplicativo começar antes de executar instâncias IHealthCheckPublisher. O atraso é aplicado uma vez na inicialização e não ocorre em iterações posteriores. O valor padrão é cinco segundos.
  • Period: o período da execução de IHealthCheckPublisher. O valor padrão é 30 segundos.
  • Predicate: se Predicate for null (padrão), o serviço do publicador de verificação de integridade executará todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que filtre o conjunto de verificações. O predicado é avaliado a cada período.
  • Timeout: o tempo limite para a execução de verificações de integridade em todas as instâncias IHealthCheckPublisher. Use InfiniteTimeSpan para executar sem um tempo limite. O valor padrão é 30 segundos.

O exemplo a seguir demonstra o layout de um publicador de integridade:

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

        return Task.CompletedTask;
    }
}

A classe HealthCheckPublisherOptions fornece propriedades para configurar o comportamento do publicador de verificação de integridade.

O exemplo a seguir registra um publicador de verificação de integridade como um banco de dados individual e 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:

  • Inclui publicadores para vários sistemas, inclusive o Application Insights.
  • Não é mantido ou com suporte da Microsoft.

Verificações de integridade individuais

Delay e Period pode ser definido em cada HealthCheckRegistration individualmente. Isso é útil quando você deseja executar algumas verificações de integridade a uma taxa diferente do período definido em HealthCheckPublisherOptions.

O código a seguir define o Delay e Period para o 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();

Injeção de dependência e verificações de integridade

É possível usar a injeção de dependência para consumir uma instância de um Type específico dentro de uma classe de Verificação de Integridade. A injeção de dependência pode ser útil para injetar opções ou uma configuração global em uma Verificação de Integridade. O uso da injeção de dependência não é um cenário comum para configurar verificações de integridade. Normalmente, cada Verificação de Integridade é bastante específica para o teste real e é configurada usando métodos de extensão IHealthChecksBuilder.

O exemplo a seguir exibe uma amostra de Verificação de Integridade que recupera um objeto de configuração por meio da injeção de dependência:

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

O SampleHealthCheckWithDiConfig e a verificação de integridade precisam ser adicionados ao contêiner de serviço :

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 vs. MapHealthChecks

Há duas maneiras de tornar as verificações de integridade acessíveis aos chamadores:

  • UseHealthChecks registra o middleware para lidar com solicitações de verificação de integridade no pipeline de middleware.
  • MapHealthChecks registra um ponto de extremidade de verificação de integridade. O ponto de extremidade é correspondido e executado junto com outros pontos de extremidade no aplicativo.

A vantagem de usar MapHealthChecks em vez de UseHealthChecks é a capacidade de usar middleware com reconhecimento de ponto de extremidade, como uma autorização, e ter maior controle refinado sobre a política de correspondência. A principal vantagem de usar UseHealthChecks em vez de MapHealthChecks é controlar exatamente onde as verificações de integridade são executadas no pipeline do middleware.

UseHealthChecks:

  • Encerra o pipeline quando uma solicitação corresponde ao ponto de extremidade de verificação de integridade. O curto-circuito geralmente é desejável porque evita trabalhos desnecessários, como registro em log e outro middleware.
  • É usado principalmente para configurar o middleware de verificação de integridade no pipeline.
  • Pode corresponder qualquer caminho em uma porta com um null ou PathString vazio. Permite executar uma verificação de integridade em qualquer solicitação feita à porta especificada.
  • Código-fonte

MapHealthChecks permite:

  • Encerrar o pipeline quando uma solicitação corresponde ao ponto de extremidade de verificação de integridade, chamando ShortCircuit. Por exemplo, app.MapHealthChecks("/healthz").ShortCircuit();. Para obter mais informações, consulte middleware de curto-circuito após o roteamento.
  • Mapear rotas ou pontos de extremidade específicos para verificações de integridade.
  • Personalizar o URL ou caminho em que o ponto de extremidade de verificação de integridade está acessível.
  • Mapear vários pontos de extremidade de verificação de integridade com diferentes rotas ou configurações. Suporte a vários pontos de extremidade:
    • Habilita pontos de extremidade separados para diferentes tipos de verificações de integridade ou componentes.
    • É usado para diferenciar entre aspectos distintos da integridade do aplicativo ou aplicar configurações específicas a subconjuntos de verificações de integridade.
  • Código-fonte

Recursos adicionais

Observação

Este artigo foi parcialmente criado com a ajuda de inteligência artificial. Antes de publicar, um autor revisou o conteúdo conforme necessário. Confira Nossos princípios para usar o conteúdo gerado por IA no Microsoft Learn.

O ASP.NET Core oferece o Middleware de Verificações de Integridade e bibliotecas para relatar a integridade de componentes de infraestrutura do aplicativo.

As verificações de integridade são expostas por um aplicativo como pontos de extremidade HTTP. Os pontos de extremidade de verificação de integridade podem ser configurados para vários cenários de monitoramento em tempo real:

  • As investigações de integridade podem ser usadas por orquestradores de contêineres e balanceadores de carga para verificar o status de um aplicativo. Por exemplo, um orquestrador de contêineres pode responder a uma verificação de integridade com falha interrompendo uma implantação sem interrupção ou reiniciando um contêiner. Um balanceador de carga pode reagir a um aplicativo não íntegro encaminhando o tráfego para fora da instância com falha para uma instância íntegra.
  • O uso de memória, disco e outros recursos de servidor físico pode ser monitorado quanto ao status de integridade.
  • As verificações de integridade podem testar as dependências do aplicativo, como bancos de dados e pontos de extremidade de serviço externo, para confirmar a disponibilidade e o funcionamento normal.

Exibir ou baixar código de exemplo (como baixar)

O aplicativo de amostra inclui exemplos dos cenários descritos neste artigo. Para executar o aplicativo de exemplo para determinado cenário, use o comando dotnet run na pasta do projeto em um shell de comando. Confira o arquivo README.md do aplicativo de amostra e as descrições de cenários neste artigo para obter detalhes sobre como usar o aplicativo de amostra.

Pré-requisitos

As verificações de integridade são normalmente usadas com um orquestrador de contêineres ou um serviço de monitoramento externo para verificar o status de um aplicativo. Antes de adicionar verificações de integridade a um aplicativo, decida qual sistema de monitoramento será usado. O sistema de monitoramento determina quais tipos de verificações de integridade serão criados e como configurar seus pontos de extremidade.

O pacote Microsoft.AspNetCore.Diagnostics.HealthChecks é referenciado implicitamente para aplicativos ASP.NET Core. Para executar verificações de integridade usando o Entity Framework Core, adicione uma referência ao pacote Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

O aplicativo de exemplo fornece um código de inicialização para demonstrar verificações de integridade para vários cenários. O cenário investigação de banco de dados verifica a integridade de uma conexão de banco de dados usando o AspNetCore.Diagnostics.HealthChecks. O cenário investigação de DbContext verifica um banco de dados usando um EF CoreDbContext. Para explorar os cenários de banco de dados, o aplicativo de exemplo:

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Outro cenário de verificação de integridade demonstra como filtrar verificações de integridade para uma porta de gerenciamento. O aplicativo de amostra exige a criação de um arquivo Properties/launchSettings.json que inclui a URL de gerenciamento e a porta de gerenciamento. Para obter mais informações, confira a seção Filtrar por porta.

Investigação de integridade básica

Para muitos aplicativos, uma configuração básica de investigação de integridade que relata a disponibilidade do aplicativo para processar solicitações (atividade) é suficiente para descobrir o status do aplicativo.

A configuração básica registra os serviços de verificação de integridade e chama o Middleware de Verificações de Integridade para responder a um ponto de extremidade de URL com uma resposta de integridade. Por padrão, nenhuma verificação de integridade específica é registrada para testar qualquer dependência ou subsistema específico. O aplicativo é considerado íntegro se consegue responder na URL do ponto de extremidade de integridade. O gravador de resposta padrão grava o status (HealthStatus) como uma resposta de texto sem formatação no cliente, indicando um status HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Registre os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks no Startup.Configure.

No aplicativo de amostra, o ponto de extremidade de verificação de integridade é criado em /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 executar o cenário de configuração básica usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario basic

Exemplo do Docker

O Docker oferece uma diretiva HEALTHCHECK interna que pode ser usada para verificar o status de um aplicativo que usa a configuração básica de verificação de integridade:

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

Criar verificações de integridade

As verificações de integridade são criadas pela implementação da interface IHealthCheck. O método CheckHealthAsync retorna um HealthCheckResult que indica a integridade como Healthy, Degraded ou Unhealthy. O resultado é gravado como uma resposta de texto sem formatação com um código de status configurável (a configuração é descrita na seção Opções de verificação de integridade). HealthCheckResult também pode retornar pares chave-valor opcionais.

A seguinte classe ExampleHealthCheck demonstra o layout de uma verificação de integridade. A lógica da verificações de integridade é colocada no método CheckHealthAsync. O exemplo a seguir define uma variável fictícia, healthCheckResultHealthy, como true. Se o valor de healthCheckResultHealthy for definido como false, o status de HealthCheckRegistration.FailureStatus será retornado.

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

Se CheckHealthAsync gerar uma exceção durante a verificação, um novo HealthReportEntry será retornado com seu HealthReportEntry.Status definido para o FailureStatus, que é definido por AddCheck (consulte a seção Registrar serviços de verificação de integridade) e incluirá a exceção interna que inicialmente causou a falha de verificação. O Description é definido como a mensagem da exceção.

Registrar os serviços de verificação de integridade

O tipo ExampleHealthCheck é adicionado aos serviços de verificação de integridade com AddCheck no Startup.ConfigureServices:

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

A sobrecarga AddCheck mostrada no exemplo a seguir define o status de falha (HealthStatus) como relatório quando a verificação de integridade relata uma falha. Se o status de falha é definido como null (padrão), HealthStatus.Unhealthy é relatado. Essa sobrecarga é um cenário útil para autores de biblioteca, em que o status de falha indicado pela biblioteca é imposto pelo aplicativo quando uma falha de verificação de integridade ocorre se a implementação da verificação de integridade respeita a configuração.

Marcas podem ser usadas para filtrar as verificações de integridade (descritas posteriormente na seção Filtrar verificações de integridade).

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

AddCheck também pode executar uma função lambda. No seguinte exemplo, o nome da verificação de integridade é especificado como Example e a verificação sempre retorna um estado íntegro:

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

Chame AddTypeActivatedCheck para aprovar argumentos para uma implementação de verificação de integridade. No exemplo a seguir, TestHealthCheckWithArgs aceita um inteiro e uma cadeia de caracteres para uso quando CheckHealthAsync é chamado:

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 é registrado chamando AddTypeActivatedCheck com o inteiro e a cadeia de caracteres aprovadas para a implementação:

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

Usar roteamento de verificações de integridade

No Startup.Configure, chame MapHealthChecks no construtor de ponto de extremidade com a URL de ponto de extremidade ou o caminho relativo:

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

Exigir host

Chame RequireHost para especificar um ou mais hosts permitidos para o ponto de extremidade de verificação de integridade. Os hosts devem ser Unicode em vez de punycode e podem incluir uma porta. Se uma coleção não for fornecida, qualquer host será aceito.

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

Para obter mais informações, confira a seção Filtrar por porta.

Exigir autorização

Chame RequireAuthorization para executar o Middleware de autorização no ponto de extremidade da solicitação de verificação de integridade. Uma sobrecarga RequireAuthorization aceita uma ou mais políticas de autorização. Se uma política não for fornecida, a política de autorização padrão será usada.

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

Habilitar o CORS (Solicitações Entre Origens)

Embora a execução manual das verificações de integridade de um navegador não seja um cenário de uso comum, o Middleware CORS pode ser habilitado chamando RequireCors nos pontos de extremidade das verificações de integridade. Uma sobrecarga RequireCors aceita um representante do construtor de políticas CORS (CorsPolicyBuilder) ou um nome de política. Se uma política não for fornecida, a política CORS padrão será usada. Para obter mais informações, consulte Habilitar solicitações entre origens (CORS, na sigla em inglês) no ASP.NET Core.

Opções de verificação de integridade

HealthCheckOptions oferece uma oportunidade de personalizar o comportamento de verificação de integridade:

Filtrar verificações de integridade

Por padrão, o Middleware de Verificações de Integridade executa todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que retorne um booliano para a opção Predicate. No seguinte exemplo, a verificação de integridade Bar é filtrada por sua marca (bar_tag) na instrução condicional da função, em que true só é retornado se a propriedade Tags da verificação de integridade corresponde a foo_tag ou baz_tag:

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

Em Startup.Configure, o Predicate filtra a verificação de integridade 'Barra'. Somente Foo e Baz executam:

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

Personalizar o código de status HTTP

Use ResultStatusCodes para personalizar o mapeamento de status da integridade para códigos de status HTTP. As atribuições StatusCodes a seguir são os valores padrão usados pelo middleware. Altere os valores do código de status de acordo com suas necessidades.

No Startup.Configure:

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

Suprimir os cabeçalhos de cache

AllowCachingResponses controla se o Middleware de verificações de integridade adiciona cabeçalhos HTTP a uma resposta de investigação para prevenir o cache de resposta. Se o valor é false (padrão), o middleware define ou substitui os cabeçalhos Cache-Control, Expires e Pragma para prevenir o cache de resposta. Se o valor é true, o middleware não modifica os cabeçalhos de cache da resposta.

No Startup.Configure:

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

Personalizar a saída

Em Startup.Configure, defina a opção HealthCheckOptions.ResponseWriter como um representante para gravar a resposta:

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

O representante padrão grava uma resposta mínima de texto sem formatação com o valor de cadeia de caracteres HealthReport.Status. Os representantes personalizados a seguir geram uma resposta JSON personalizada.

O primeiro exemplo do aplicativo de amostra demonstra como 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);
    }
}

O segundo exemplo demonstra como 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));
}

No aplicativo de amostra, comente a SYSTEM_TEXT_JSONdiretiva de pré-processador em CustomWriterStartup.cs para habilitar a versão Newtonsoft.Json do WriteResponse.

A API de verificações de integridade não fornece suporte interno para formatos de retorno JSON complexos porque o formato é específico para sua escolha de sistema de monitoramento. Personalize a resposta nos exemplos anteriores, conforme necessário. Para obter mais informações sobre a serialização JSON com System.Text.Json, consulte Como serializar e desserializar JSON no .NET.

Investigação de banco de dados

Uma verificação de integridade pode especificar uma consulta de banco de dados a ser executada como um teste booliano para indicar se o banco de dados está respondendo normalmente.

O aplicativo de amostra usa o AspNetCore.Diagnostics.HealthChecks, uma biblioteca de verificação de integridade para aplicativos do ASP.NET Core, para executar uma verificação de integridade em um banco de dados do SQL Server. O AspNetCore.Diagnostics.HealthChecks executa uma consulta SELECT 1 no banco de dados para confirmar se a conexão ao banco de dados está íntegra.

Aviso

Ao verificar uma conexão de banco de dados com uma consulta, escolha uma consulta que retorne rapidamente. A abordagem de consulta corre o risco de sobrecarregar o banco de dados e prejudicar o desempenho. Na maioria dos casos, a execução de uma consulta de teste não é necessária. É suficiente apenas estabelecer uma conexão bem-sucedida ao banco de dados. Se você achar necessário executar uma consulta, escolha uma consulta SELECT simples, como SELECT 1.

Inclui uma referência de pacote para AspNetCore.HealthChecks.SqlServer.

Forneça uma cadeia de conexão de banco de dados válida no arquivo appsettings.json do aplicativo de amostra. O aplicativo usa um banco de dados do SQL Server chamado 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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. O aplicativo de amostra chama o método AddSqlServer com a cadeia de conexão do banco de dados (DbHealthStartup.cs):

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure:

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

Para executar o cenário de investigação de banco de dados usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario db

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Investigação de DbContext do Entity Framework Core

A verificação DbContext confirma se o aplicativo pode se comunicar com o banco de dados configurado para um EF CoreDbContext. A verificação DbContext é compatível em aplicativos que:

AddDbContextCheck<TContext> registra uma verificação de integridade para um DbContext. O DbContext é fornecido como o TContext para o método. Uma sobrecarga está disponível para configurar o status de falha, marcas e uma consulta de teste personalizada.

Por padrão:

  • O DbContextHealthCheck chama o método CanConnectAsync do EF Core. Você pode personalizar qual operação é executada durante a verificação de integridade usando sobrecargas do método AddDbContextCheck.
  • O nome da verificação de integridade é o nome do tipo TContext.

No aplicativo de amostra, AppDbContext é fornecido para AddDbContextCheck e registrado como um serviço em Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure:

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

Para executar o cenário de investigação DbContext usando o aplicativo de exemplo, confirme se o banco de dados especificado pela cadeia de conexão não existe na instância do SQL Server. Se o banco de dados existir, exclua-o.

Execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario dbcontext

Depois que o aplicativo estiver em execução, verifique o status da integridade fazendo uma solicitação para o ponto de extremidade /health em um navegador. O banco de dados e AppDbContext não existem e, portanto, o aplicativo fornece a seguinte resposta:

Unhealthy

Dispare o aplicativo de exemplo para criar o banco de dados. Faça uma solicitação para /createdatabase. O aplicativo responde:

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

Faça uma solicitação ao ponto de extremidade /health. O banco de dados e o contexto existem e, portanto, o aplicativo responde:

Healthy

Dispare o aplicativo de exemplo para excluir o banco de dados. Faça uma solicitação para /deletedatabase. O aplicativo responde:

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

Faça uma solicitação ao ponto de extremidade /health. O aplicativo fornece uma resposta não íntegra:

Unhealthy

Investigações de preparação e atividade separadas

Em alguns cenários de hospedagem, é usado um par de verificações de integridade que distingue dois estados de aplicativo:

  • Preparação indica se o aplicativo está em execução normalmente, mas não está pronto para receber solicitações.
  • Atividade indica se um aplicativo falhou e deve ser reiniciado.

Considere o exemplo a seguir: um aplicativo deve baixar um arquivo de configuração grande antes de estar pronto para processar solicitações. Não queremos que o aplicativo seja reiniciado se o download inicial falhar porque o aplicativo pode tentar baixar o arquivo novamente várias vezes. Usamos uma investigação de atividade para descrever a atividade do processo; nenhuma outra verificação é executada. Também queremos impedir que as solicitações sejam enviadas ao aplicativo antes que o download do arquivo de configuração seja bem-sucedido. Usamos uma investigação de preparação para indicar um estado "não pronto" até que o download seja bem-sucedido e o aplicativo esteja pronto para receber solicitações.

O aplicativo de exemplo contém uma verificação de integridade para relatar a conclusão da tarefa de inicialização de execução longa em um Serviço Hospedado. O StartupHostedServiceHealthCheck expõe uma propriedade, StartupTaskCompleted, que o serviço hospedado poderá definir como true quando sua tarefa de execução longa estiver concluída (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."));
    }
}

A tarefa em segundo plano de execução longa é iniciada por um Serviço Hospedado (Services/StartupHostedService). Após a conclusão da tarefa, StartupHostedServiceHealthCheck.StartupTaskCompleted é definido como 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()
    {
    }
}

A verificação de integridade é registrada em AddCheck no Startup.ConfigureServices juntamente com o serviço hospedado. Como o serviço hospedado precisa definir a propriedade na verificação de integridade, a verificação de integridade também é registrada no contêiner de serviço (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>();

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure. No aplicativo de amostra, os pontos de extremidade de verificação de integridade são criados em:

  • /health/ready para a verificação de preparação. A verificação de preparação filtra as verificações de integridade para a verificação de integridade com a marca ready.
  • /health/live para a verificação de atividade. A verificação de atividade filtra o StartupHostedServiceHealthCheck retornando false no HealthCheckOptions.Predicate (para obter mais informações, consulte Filtrar verificações de integridade)

No código de exemplo a seguir:

  • A verificação de preparação usa todas as verificações registradas com a marcação "pronta".
  • O Predicate exclui todas as verificações e retorna um 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 executar o cenário de configuração de preparação/atividade usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario liveness

Em um navegador, visite /health/ready várias vezes até terem decorrido 15 segundos. A verificação de integridade relata Unhealthy para os primeiros 15 segundos. Após 15 segundos, o ponto de extremidade relata Healthy, que reflete a conclusão da tarefa de execução longa pelo serviço hospedado.

Esse exemplo também cria um Publicador de Verificação de Integridade (implementação de IHealthCheckPublisher) que executa a primeira verificação de preparação com um atraso de dois segundos. Para saber mais, confira a seção Publicador de Verificação de Integridade.

Exemplo do Kubernetes

O uso de verificações de preparação e atividade separadas é útil em um ambiente como o Kubernetes. No Kubernetes, um aplicativo pode precisar executar um trabalho de inicialização demorado antes de aceitar solicitações, como um teste da disponibilidade do banco de dados subjacente. O uso de verificações separadas permite que o orquestrador distinga se o aplicativo está funcionando, mas ainda não está pronto, ou se o aplicativo falhou ao ser iniciado. Para obter mais informações sobre as investigações de preparação e atividade no Kubernetes, confira Configurar investigações de preparação e atividade na documentação do Kubernetes.

O seguinte exemplo demonstra uma configuração de investigação de preparação do 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

Investigação baseada em métrica com um gravador de resposta personalizada

O aplicativo de exemplo demonstra uma verificação de integridade da memória com um gravador de resposta personalizada.

MemoryHealthCheck relata um estado degradado se o aplicativo usa mais de determinado limite de memória (1 GB no aplicativo de exemplo). O HealthCheckResult inclui informações de Coletor de Lixo (GC, na sigla em inglês) para o aplicativo (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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Em vez de permitir a verificação de integridade passando-a para AddCheck, a MemoryHealthCheck é registrada como um serviço. Todos os serviços registrados da IHealthCheck estão disponíveis para os serviços de verificação de integridade e middleware. Recomendamos registrar os serviços de verificação de integridade como serviços Singleton.

Em CustomWriterStartup.cs do aplicativo de amostra:

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure. Um representante WriteResponse é fornecido para a propriedade ResponseWriter para gerar uma resposta JSON personalizada quando a verificação de integridade é executada:

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

O representante WriteResponse formata o CompositeHealthCheckResult em um objeto JSON e produz a saída JSON para a resposta da verificação de integridade. Para obter mais informações, consulte a seção Personalizar saída.

Para executar a investigação baseada em métrica com a saída do gravador de resposta personalizada usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario writer

Observação

O AspNetCore.Diagnostics.HealthChecks inclui cenários de verificação de integridade baseada em métrica, incluindo verificações de atividade de valor máximo e armazenamento em disco.

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Filtrar por porta

Chame RequireHost em MapHealthChecks com um padrão de URL que especifica uma porta para restringir as solicitações de verificação de integridade à porta especificada. Essa abordagem normalmente é usada em um ambiente de contêiner para expor uma porta para os serviços de monitoramento.

O aplicativo de exemplo configura a porta usando o Provedor de Configuração de Variáveis de Ambiente. A porta é definida no arquivo launchSettings.json e aprovada para o provedor de configuração por meio de uma variável de ambiente. Você também precisa configurar o servidor para escutar as solicitações na porta de gerenciamento.

Para usar o aplicativo de amostra para demonstrar a configuração da porta de gerenciamento, crie o arquivo launchSettings.json em uma pasta Properties.

O arquivo Properties/launchSettings.json a seguir no aplicativo de amostra não está incluído nos arquivos de projeto do aplicativo de amostra e precisa ser criado 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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks no Startup.Configure.

No aplicativo de amostra, uma chamada para RequireHost no ponto de extremidade em Startup.Configure especifica a porta de gerenciamento da configuração:

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

Os pontos de extremidade são criados no aplicativo de amostra em Startup.Configure. No código de exemplo a seguir:

  • A verificação de preparação usa todas as verificações registradas com a marcação "pronta".
  • O Predicate exclui todas as verificações e retorna um 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
    });
}

Observação

Evite a criação do arquivo launchSettings.json no aplicativo de amostra definindo a porta de gerenciamento explicitamente no código. Em Program.cs, em que o HostBuilder é criado, adicione uma chamada a ListenAnyIP e forneça o ponto de extremidade da porta de gerenciamento do aplicativo. Em Configure do ManagementPortStartup.cs, especifique a porta de gerenciamento com 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 executar o cenário de configuração de porta de gerenciamento usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario port

Distribuir uma biblioteca de verificação de integridade

Para distribuir uma verificação de integridade como uma biblioteca:

  1. Escreva uma verificação de integridade que implementa a interface IHealthCheck como uma classe autônoma. A classe pode depender da DI (injeção de dependência), da ativação de tipo e das opções nomeadas para acessar os dados de configuração.

    Na lógica de verificações de integridade do CheckHealthAsync:

    • data1 e data2 são usados no método para executar a lógica de verificação de integridade da investigação.
    • AccessViolationException é tratado.

    Quando ocorre um AccessViolationException, o FailureStatus é retornado com o HealthCheckResult para permitir que os usuários configurem o status da falha de verificações de integridade.

    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. Escreva um método de extensão com parâmetros que o aplicativo de consumo chama em seu método Startup.Configure. No seguinte exemplo, suponha a seguinte assinatura de método de verificação de integridade:

    ExampleHealthCheck(string, string, int )
    

    A assinatura anterior indica que a ExampleHealthCheck exige dados adicionais para processar a lógica de investigação de verificação de integridade. Os dados são fornecidos para o representante usado para criar a instância de verificação de integridade quando a verificação de integridade é registrada em um método de extensão. No seguinte exemplo, o chamador especifica itens opcionais:

    • nome da verificação de integridade (name). Se null, example_health_check é usado.
    • ponto de dados de cadeia de caracteres para a verificação de integridade (data1).
    • ponto de dados de inteiro para a verificação de integridade (data2). Se null, 1 é usado.
    • status de falha (HealthStatus). O padrão é null. Se null, HealthStatus.Unhealthy é relatado para um status de falha.
    • marcas (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 Verificação de Integridade

Quando um IHealthCheckPublisher é adicionado ao contêiner de serviços, o sistema de verificação de integridade periodicamente executa sua verificação de integridade e chama PublishAsync com o resultado. Isso é útil em um cenário de sistema de monitoramento de integridade baseada em push que espera que cada processo chame o sistema de monitoramento periodicamente para determinar a integridade.

A interface IHealthCheckPublisher tem um único método:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions permite que você defina:

  • Delay: o atraso inicial aplicado após o aplicativo começar antes de executar instâncias IHealthCheckPublisher. O atraso é aplicado uma vez na inicialização e não ocorre em iterações subsequentes. O valor padrão é cinco segundos.
  • Period: o período da execução de IHealthCheckPublisher. O valor padrão é 30 segundos.
  • Predicate: se Predicate for null (padrão), o serviço do publicador de verificação de integridade executará todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que filtre o conjunto de verificações. O predicado é avaliado a cada período.
  • Timeout: o tempo limite para a execução de verificações de integridade em todas as instâncias IHealthCheckPublisher. Use InfiniteTimeSpan para executar sem um tempo limite. O valor padrão é 30 segundos.

No aplicativo de exemplo, ReadinessPublisher é uma implementação IHealthCheckPublisher. O status da verificação de integridade é registrado para cada verificação em um nível de log 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;
    }
}

No exemplo LivenessProbeStartup do aplicativo de amostra, a verificação de preparação StartupHostedService tem um atraso de inicialização de dois segundos, e executa a verificação a cada 30 segundos. Para ativar a implementação IHealthCheckPublisher, o exemplo registra ReadinessPublisher como um serviço singleton no contêiner DI (injeção de dependência):

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>();

Observação

O AspNetCore.Diagnostics.HealthChecks inclui publicadores para vários sistemas, incluindo o Application Insights.

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Restringir verificações de integridade com MapWhen

Use MapWhen para ramificar condicionalmente o pipeline de solicitação para pontos de extremidade de verificação de integridade.

No exemplo a seguir, MapWhen ramificará o pipeline de solicitação para ativar o Middleware de verificações de integridade se uma solicitação GET for recebida no ponto de extremidade 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 obter mais informações, confira Middleware do ASP.NET Core.

O ASP.NET Core oferece o Middleware de Verificações de Integridade e bibliotecas para relatar a integridade de componentes de infraestrutura do aplicativo.

As verificações de integridade são expostas por um aplicativo como pontos de extremidade HTTP. Os pontos de extremidade de verificação de integridade podem ser configurados para vários cenários de monitoramento em tempo real:

  • As investigações de integridade podem ser usadas por orquestradores de contêineres e balanceadores de carga para verificar o status de um aplicativo. Por exemplo, um orquestrador de contêineres pode responder a uma verificação de integridade com falha interrompendo uma implantação sem interrupção ou reiniciando um contêiner. Um balanceador de carga pode reagir a um aplicativo não íntegro encaminhando o tráfego para fora da instância com falha para uma instância íntegra.
  • O uso de memória, disco e outros recursos de servidor físico pode ser monitorado quanto ao status de integridade.
  • As verificações de integridade podem testar as dependências do aplicativo, como bancos de dados e pontos de extremidade de serviço externo, para confirmar a disponibilidade e o funcionamento normal.

Exibir ou baixar código de exemplo (como baixar)

O aplicativo de amostra inclui exemplos dos cenários descritos neste artigo. Para executar o aplicativo de exemplo para determinado cenário, use o comando dotnet run na pasta do projeto em um shell de comando. Confira o arquivo README.md do aplicativo de amostra e as descrições de cenários neste artigo para obter detalhes sobre como usar o aplicativo de amostra.

Pré-requisitos

As verificações de integridade são normalmente usadas com um orquestrador de contêineres ou um serviço de monitoramento externo para verificar o status de um aplicativo. Antes de adicionar verificações de integridade a um aplicativo, decida qual sistema de monitoramento será usado. O sistema de monitoramento determina quais tipos de verificações de integridade serão criados e como configurar seus pontos de extremidade.

O pacote Microsoft.AspNetCore.Diagnostics.HealthChecks é referenciado implicitamente para aplicativos ASP.NET Core. Para executar verificações de integridade usando o Entity Framework Core, adicione uma referência de pacote ao pacote Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

O aplicativo de exemplo fornece um código de inicialização para demonstrar verificações de integridade para vários cenários. O cenário investigação de banco de dados verifica a integridade de uma conexão de banco de dados usando o AspNetCore.Diagnostics.HealthChecks. O cenário investigação de DbContext verifica um banco de dados usando um EF CoreDbContext. Para explorar os cenários de banco de dados, o aplicativo de exemplo:

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Outro cenário de verificação de integridade demonstra como filtrar verificações de integridade para uma porta de gerenciamento. O aplicativo de amostra exige a criação de um arquivo Properties/launchSettings.json que inclui a URL de gerenciamento e a porta de gerenciamento. Para obter mais informações, confira a seção Filtrar por porta.

Investigação de integridade básica

Para muitos aplicativos, uma configuração básica de investigação de integridade que relata a disponibilidade do aplicativo para processar solicitações (atividade) é suficiente para descobrir o status do aplicativo.

A configuração básica registra os serviços de verificação de integridade e chama o Middleware de Verificações de Integridade para responder a um ponto de extremidade de URL com uma resposta de integridade. Por padrão, nenhuma verificação de integridade específica é registrada para testar qualquer dependência ou subsistema específico. O aplicativo é considerado íntegro se consegue responder na URL do ponto de extremidade de integridade. O gravador de resposta padrão grava o status (HealthStatus) como uma resposta de texto sem formatação no cliente, indicando um status HealthStatus.Healthy, HealthStatus.Degraded ou HealthStatus.Unhealthy.

Registre os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks no Startup.Configure.

No aplicativo de amostra, o ponto de extremidade de verificação de integridade é criado em /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 executar o cenário de configuração básica usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario basic

Exemplo do Docker

O Docker oferece uma diretiva HEALTHCHECK interna que pode ser usada para verificar o status de um aplicativo que usa a configuração básica de verificação de integridade:

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

Criar verificações de integridade

As verificações de integridade são criadas pela implementação da interface IHealthCheck. O método CheckHealthAsync retorna um HealthCheckResult que indica a integridade como Healthy, Degraded ou Unhealthy. O resultado é gravado como uma resposta de texto sem formatação com um código de status configurável (a configuração é descrita na seção Opções de verificação de integridade). HealthCheckResult também pode retornar pares chave-valor opcionais.

A seguinte classe ExampleHealthCheck demonstra o layout de uma verificação de integridade. A lógica da verificações de integridade é colocada no método CheckHealthAsync. O exemplo a seguir define uma variável fictícia, healthCheckResultHealthy, como true. Se o valor de healthCheckResultHealthy for definido como false, o status de HealthCheckResult.Unhealthy será retornado.

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

Registrar os serviços de verificação de integridade

O tipo ExampleHealthCheck é adicionado aos serviços de verificação de integridade com AddCheck no Startup.ConfigureServices:

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

A sobrecarga AddCheck mostrada no exemplo a seguir define o status de falha (HealthStatus) como relatório quando a verificação de integridade relata uma falha. Se o status de falha é definido como null (padrão), HealthStatus.Unhealthy é relatado. Essa sobrecarga é um cenário útil para autores de biblioteca, em que o status de falha indicado pela biblioteca é imposto pelo aplicativo quando uma falha de verificação de integridade ocorre se a implementação da verificação de integridade respeita a configuração.

Marcas podem ser usadas para filtrar as verificações de integridade (descritas posteriormente na seção Filtrar verificações de integridade).

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

AddCheck também pode executar uma função lambda. No seguinte exemplo, o nome da verificação de integridade é especificado como Example e a verificação sempre retorna um estado íntegro:

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

Chame AddTypeActivatedCheck para aprovar argumentos para uma implementação de verificação de integridade. No exemplo a seguir, TestHealthCheckWithArgs aceita um inteiro e uma cadeia de caracteres para uso quando CheckHealthAsync é chamado:

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 é registrado chamando AddTypeActivatedCheck com o inteiro e a cadeia de caracteres aprovadas para a implementação:

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

Usar roteamento de verificações de integridade

No Startup.Configure, chame MapHealthChecks no construtor de ponto de extremidade com a URL de ponto de extremidade ou o caminho relativo:

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

Exigir host

Chame RequireHost para especificar um ou mais hosts permitidos para o ponto de extremidade de verificação de integridade. Os hosts devem ser Unicode em vez de punycode e podem incluir uma porta. Se uma coleção não for fornecida, qualquer host será aceito.

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

Para obter mais informações, confira a seção Filtrar por porta.

Exigir autorização

Chame RequireAuthorization para executar o Middleware de autorização no ponto de extremidade da solicitação de verificação de integridade. Uma sobrecarga RequireAuthorization aceita uma ou mais políticas de autorização. Se uma política não for fornecida, a política de autorização padrão será usada.

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

Habilitar o CORS (Solicitações Entre Origens)

Embora a execução manual das verificações de integridade de um navegador não seja um cenário de uso comum, o Middleware CORS pode ser habilitado chamando RequireCors nos pontos de extremidade das verificações de integridade. Uma sobrecarga RequireCors aceita um representante do construtor de políticas CORS (CorsPolicyBuilder) ou um nome de política. Se uma política não for fornecida, a política CORS padrão será usada. Para obter mais informações, consulte Habilitar solicitações entre origens (CORS, na sigla em inglês) no ASP.NET Core.

Opções de verificação de integridade

HealthCheckOptions oferece uma oportunidade de personalizar o comportamento de verificação de integridade:

Filtrar verificações de integridade

Por padrão, o Middleware de Verificações de Integridade executa todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que retorne um booliano para a opção Predicate. No seguinte exemplo, a verificação de integridade Bar é filtrada por sua marca (bar_tag) na instrução condicional da função, em que true só é retornado se a propriedade Tags da verificação de integridade corresponde a foo_tag ou baz_tag:

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

Em Startup.Configure, o Predicate filtra a verificação de integridade 'Barra'. Somente Foo e Baz executam:

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

Personalizar o código de status HTTP

Use ResultStatusCodes para personalizar o mapeamento de status da integridade para códigos de status HTTP. As atribuições StatusCodes a seguir são os valores padrão usados pelo middleware. Altere os valores do código de status de acordo com suas necessidades.

No Startup.Configure:

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

Suprimir os cabeçalhos de cache

AllowCachingResponses controla se o Middleware de verificações de integridade adiciona cabeçalhos HTTP a uma resposta de investigação para prevenir o cache de resposta. Se o valor é false (padrão), o middleware define ou substitui os cabeçalhos Cache-Control, Expires e Pragma para prevenir o cache de resposta. Se o valor é true, o middleware não modifica os cabeçalhos de cache da resposta.

No Startup.Configure:

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

Personalizar a saída

Em Startup.Configure, defina a opção HealthCheckOptions.ResponseWriter como um representante para gravar a resposta:

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

O representante padrão grava uma resposta mínima de texto sem formatação com o valor de cadeia de caracteres HealthReport.Status. Os representantes personalizados a seguir geram uma resposta JSON personalizada.

O primeiro exemplo do aplicativo de amostra demonstra como 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);
    }
}

O segundo exemplo demonstra como 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));
}

No aplicativo de amostra, comente a SYSTEM_TEXT_JSONdiretiva de pré-processador em CustomWriterStartup.cs para habilitar a versão Newtonsoft.Json do WriteResponse.

A API de verificações de integridade não fornece suporte interno para formatos de retorno JSON complexos porque o formato é específico para sua escolha de sistema de monitoramento. Personalize a resposta nos exemplos anteriores, conforme necessário. Para obter mais informações sobre a serialização JSON com System.Text.Json, consulte Como serializar e desserializar JSON no .NET.

Investigação de banco de dados

Uma verificação de integridade pode especificar uma consulta de banco de dados a ser executada como um teste booliano para indicar se o banco de dados está respondendo normalmente.

O aplicativo de amostra usa o AspNetCore.Diagnostics.HealthChecks, uma biblioteca de verificação de integridade para aplicativos do ASP.NET Core, para executar uma verificação de integridade em um banco de dados do SQL Server. O AspNetCore.Diagnostics.HealthChecks executa uma consulta SELECT 1 no banco de dados para confirmar se a conexão ao banco de dados está íntegra.

Aviso

Ao verificar uma conexão de banco de dados com uma consulta, escolha uma consulta que retorne rapidamente. A abordagem de consulta corre o risco de sobrecarregar o banco de dados e prejudicar o desempenho. Na maioria dos casos, a execução de uma consulta de teste não é necessária. É suficiente apenas estabelecer uma conexão bem-sucedida ao banco de dados. Se você achar necessário executar uma consulta, escolha uma consulta SELECT simples, como SELECT 1.

Inclui uma referência de pacote para AspNetCore.HealthChecks.SqlServer.

Forneça uma cadeia de conexão de banco de dados válida no arquivo appsettings.json do aplicativo de amostra. O aplicativo usa um banco de dados do SQL Server chamado 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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. O aplicativo de amostra chama o método AddSqlServer com a cadeia de conexão do banco de dados (DbHealthStartup.cs):

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure:

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

Para executar o cenário de investigação de banco de dados usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario db

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Investigação de DbContext do Entity Framework Core

A verificação DbContext confirma se o aplicativo pode se comunicar com o banco de dados configurado para um EF CoreDbContext. A verificação DbContext é compatível em aplicativos que:

AddDbContextCheck<TContext> registra uma verificação de integridade para um DbContext. O DbContext é fornecido como o TContext para o método. Uma sobrecarga está disponível para configurar o status de falha, marcas e uma consulta de teste personalizada.

Por padrão:

  • O DbContextHealthCheck chama o método CanConnectAsync do EF Core. Você pode personalizar qual operação é executada durante a verificação de integridade usando sobrecargas do método AddDbContextCheck.
  • O nome da verificação de integridade é o nome do tipo TContext.

No aplicativo de amostra, AppDbContext é fornecido para AddDbContextCheck e registrado como um serviço em Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure:

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

Para executar o cenário de investigação DbContext usando o aplicativo de exemplo, confirme se o banco de dados especificado pela cadeia de conexão não existe na instância do SQL Server. Se o banco de dados existir, exclua-o.

Execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario dbcontext

Depois que o aplicativo estiver em execução, verifique o status da integridade fazendo uma solicitação para o ponto de extremidade /health em um navegador. O banco de dados e AppDbContext não existem e, portanto, o aplicativo fornece a seguinte resposta:

Unhealthy

Dispare o aplicativo de exemplo para criar o banco de dados. Faça uma solicitação para /createdatabase. O aplicativo responde:

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

Faça uma solicitação ao ponto de extremidade /health. O banco de dados e o contexto existem e, portanto, o aplicativo responde:

Healthy

Dispare o aplicativo de exemplo para excluir o banco de dados. Faça uma solicitação para /deletedatabase. O aplicativo responde:

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

Faça uma solicitação ao ponto de extremidade /health. O aplicativo fornece uma resposta não íntegra:

Unhealthy

Investigações de preparação e atividade separadas

Em alguns cenários de hospedagem, é usado um par de verificações de integridade que distingue dois estados de aplicativo:

  • Preparação indica se o aplicativo está em execução normalmente, mas não está pronto para receber solicitações.
  • Atividade indica se um aplicativo falhou e deve ser reiniciado.

Considere o exemplo a seguir: um aplicativo deve baixar um arquivo de configuração grande antes de estar pronto para processar solicitações. Não queremos que o aplicativo seja reiniciado se o download inicial falhar porque o aplicativo pode tentar baixar o arquivo novamente várias vezes. Usamos uma investigação de atividade para descrever a atividade do processo; nenhuma outra verificação é executada. Também queremos impedir que as solicitações sejam enviadas ao aplicativo antes que o download do arquivo de configuração seja bem-sucedido. Usamos uma investigação de preparação para indicar um estado "não pronto" até que o download seja bem-sucedido e o aplicativo esteja pronto para receber solicitações.

O aplicativo de exemplo contém uma verificação de integridade para relatar a conclusão da tarefa de inicialização de execução longa em um Serviço Hospedado. O StartupHostedServiceHealthCheck expõe uma propriedade, StartupTaskCompleted, que o serviço hospedado poderá definir como true quando sua tarefa de execução longa estiver concluída (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."));
    }
}

A tarefa em segundo plano de execução longa é iniciada por um Serviço Hospedado (Services/StartupHostedService). Após a conclusão da tarefa, StartupHostedServiceHealthCheck.StartupTaskCompleted é definido como 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()
    {
    }
}

A verificação de integridade é registrada em AddCheck no Startup.ConfigureServices juntamente com o serviço hospedado. Como o serviço hospedado precisa definir a propriedade na verificação de integridade, a verificação de integridade também é registrada no contêiner de serviço (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>();

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure. No aplicativo de amostra, os pontos de extremidade de verificação de integridade são criados em:

  • /health/ready para a verificação de preparação. A verificação de preparação filtra as verificações de integridade para a verificação de integridade com a marca ready.
  • /health/live para a verificação de atividade. A verificação de atividade filtra o StartupHostedServiceHealthCheck retornando false no HealthCheckOptions.Predicate (para obter mais informações, consulte Filtrar verificações de integridade)

No código de exemplo a seguir:

  • A verificação de preparação usa todas as verificações registradas com a marcação "pronta".
  • O Predicate exclui todas as verificações e retorna um 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 executar o cenário de configuração de preparação/atividade usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario liveness

Em um navegador, visite /health/ready várias vezes até terem decorrido 15 segundos. A verificação de integridade relata Unhealthy para os primeiros 15 segundos. Após 15 segundos, o ponto de extremidade relata Healthy, que reflete a conclusão da tarefa de execução longa pelo serviço hospedado.

Esse exemplo também cria um Publicador de Verificação de Integridade (implementação de IHealthCheckPublisher) que executa a primeira verificação de preparação com um atraso de dois segundos. Para saber mais, confira a seção Publicador de Verificação de Integridade.

Exemplo do Kubernetes

O uso de verificações de preparação e atividade separadas é útil em um ambiente como o Kubernetes. No Kubernetes, um aplicativo pode precisar executar um trabalho de inicialização demorado antes de aceitar solicitações, como um teste da disponibilidade do banco de dados subjacente. O uso de verificações separadas permite que o orquestrador distinga se o aplicativo está funcionando, mas ainda não está pronto, ou se o aplicativo falhou ao ser iniciado. Para obter mais informações sobre as investigações de preparação e atividade no Kubernetes, confira Configurar investigações de preparação e atividade na documentação do Kubernetes.

O seguinte exemplo demonstra uma configuração de investigação de preparação do 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

Investigação baseada em métrica com um gravador de resposta personalizada

O aplicativo de exemplo demonstra uma verificação de integridade da memória com um gravador de resposta personalizada.

MemoryHealthCheck relata um estado degradado se o aplicativo usa mais de determinado limite de memória (1 GB no aplicativo de exemplo). O HealthCheckResult inclui informações de Coletor de Lixo (GC, na sigla em inglês) para o aplicativo (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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Em vez de permitir a verificação de integridade passando-a para AddCheck, a MemoryHealthCheck é registrada como um serviço. Todos os serviços registrados da IHealthCheck estão disponíveis para os serviços de verificação de integridade e middleware. Recomendamos registrar os serviços de verificação de integridade como serviços Singleton.

Em CustomWriterStartup.cs do aplicativo de amostra:

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

Um ponto de extremidade de verificação de integridade é criado chamando MapHealthChecks em Startup.Configure. Um representante WriteResponse é fornecido para a propriedade ResponseWriter para gerar uma resposta JSON personalizada quando a verificação de integridade é executada:

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

O representante WriteResponse formata o CompositeHealthCheckResult em um objeto JSON e produz a saída JSON para a resposta da verificação de integridade. Para obter mais informações, consulte a seção Personalizar saída.

Para executar a investigação baseada em métrica com a saída do gravador de resposta personalizada usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario writer

Observação

O AspNetCore.Diagnostics.HealthChecks inclui cenários de verificação de integridade baseada em métrica, incluindo verificações de atividade de valor máximo e armazenamento em disco.

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Filtrar por porta

Chame RequireHost em MapHealthChecks com um padrão de URL que especifica uma porta para restringir as solicitações de verificação de integridade à porta especificada. Essa abordagem normalmente é usada em um ambiente de contêiner para expor uma porta para os serviços de monitoramento.

O aplicativo de exemplo configura a porta usando o Provedor de Configuração de Variáveis de Ambiente. A porta é definida no arquivo launchSettings.json e aprovada para o provedor de configuração por meio de uma variável de ambiente. Você também precisa configurar o servidor para escutar as solicitações na porta de gerenciamento.

Para usar o aplicativo de amostra para demonstrar a configuração da porta de gerenciamento, crie o arquivo launchSettings.json em uma pasta Properties.

O arquivo Properties/launchSettings.json a seguir no aplicativo de amostra não está incluído nos arquivos de projeto do aplicativo de amostra e precisa ser criado 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 os serviços de verificação de integridade com AddHealthChecks em Startup.ConfigureServices. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks no Startup.Configure.

No aplicativo de amostra, uma chamada para RequireHost no ponto de extremidade em Startup.Configure especifica a porta de gerenciamento da configuração:

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

Os pontos de extremidade são criados no aplicativo de amostra em Startup.Configure. No código de exemplo a seguir:

  • A verificação de preparação usa todas as verificações registradas com a marcação "pronta".
  • O Predicate exclui todas as verificações e retorna um 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
    });
}

Observação

Evite a criação do arquivo launchSettings.json no aplicativo de amostra definindo a porta de gerenciamento explicitamente no código. Em Program.cs, em que o HostBuilder é criado, adicione uma chamada a ListenAnyIP e forneça o ponto de extremidade da porta de gerenciamento do aplicativo. Em Configure do ManagementPortStartup.cs, especifique a porta de gerenciamento com 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 executar o cenário de configuração de porta de gerenciamento usando o aplicativo de exemplo, execute o seguinte comando na pasta do projeto em um shell de comando:

dotnet run --scenario port

Distribuir uma biblioteca de verificação de integridade

Para distribuir uma verificação de integridade como uma biblioteca:

  1. Escreva uma verificação de integridade que implementa a interface IHealthCheck como uma classe autônoma. A classe pode depender da DI (injeção de dependência), da ativação de tipo e das opções nomeadas para acessar os dados de configuração.

    Na lógica de verificações de integridade do CheckHealthAsync:

    • data1 e data2 são usados no método para executar a lógica de verificação de integridade da investigação.
    • AccessViolationException é tratado.

    Quando ocorre um AccessViolationException, o FailureStatus é retornado com o HealthCheckResult para permitir que os usuários configurem o status da falha de verificações de integridade.

    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. Escreva um método de extensão com parâmetros que o aplicativo de consumo chama em seu método Startup.Configure. No seguinte exemplo, suponha a seguinte assinatura de método de verificação de integridade:

    ExampleHealthCheck(string, string, int )
    

    A assinatura anterior indica que a ExampleHealthCheck exige dados adicionais para processar a lógica de investigação de verificação de integridade. Os dados são fornecidos para o representante usado para criar a instância de verificação de integridade quando a verificação de integridade é registrada em um método de extensão. No seguinte exemplo, o chamador especifica itens opcionais:

    • nome da verificação de integridade (name). Se null, example_health_check é usado.
    • ponto de dados de cadeia de caracteres para a verificação de integridade (data1).
    • ponto de dados de inteiro para a verificação de integridade (data2). Se null, 1 é usado.
    • status de falha (HealthStatus). O padrão é null. Se null, HealthStatus.Unhealthy é relatado para um status de falha.
    • marcas (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 Verificação de Integridade

Quando um IHealthCheckPublisher é adicionado ao contêiner de serviços, o sistema de verificação de integridade periodicamente executa sua verificação de integridade e chama PublishAsync com o resultado. Isso é útil em um cenário de sistema de monitoramento de integridade baseada em push que espera que cada processo chame o sistema de monitoramento periodicamente para determinar a integridade.

A interface IHealthCheckPublisher tem um único método:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions permite que você defina:

  • Delay: o atraso inicial aplicado após o aplicativo começar antes de executar instâncias IHealthCheckPublisher. O atraso é aplicado uma vez na inicialização e não ocorre em iterações subsequentes. O valor padrão é cinco segundos.
  • Period: o período da execução de IHealthCheckPublisher. O valor padrão é 30 segundos.
  • Predicate: se Predicate for null (padrão), o serviço do publicador de verificação de integridade executará todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que filtre o conjunto de verificações. O predicado é avaliado a cada período.
  • Timeout: o tempo limite para a execução de verificações de integridade em todas as instâncias IHealthCheckPublisher. Use InfiniteTimeSpan para executar sem um tempo limite. O valor padrão é 30 segundos.

No aplicativo de exemplo, ReadinessPublisher é uma implementação IHealthCheckPublisher. O status da verificação de integridade é registrado para cada verificação em um nível de log 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;
    }
}

No exemplo LivenessProbeStartup do aplicativo de amostra, a verificação de preparação StartupHostedService tem um atraso de inicialização de dois segundos, e executa a verificação a cada 30 segundos. Para ativar a implementação IHealthCheckPublisher, o exemplo registra ReadinessPublisher como um serviço singleton no contêiner DI (injeção de dependência):

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>();

Observação

O AspNetCore.Diagnostics.HealthChecks inclui publicadores para vários sistemas, incluindo o Application Insights.

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Restringir verificações de integridade com MapWhen

Use MapWhen para ramificar condicionalmente o pipeline de solicitação para pontos de extremidade de verificação de integridade.

No exemplo a seguir, MapWhen ramificará o pipeline de solicitação para ativar o Middleware de verificações de integridade se uma solicitação GET for recebida no ponto de extremidade 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 obter mais informações, confira Middleware do ASP.NET Core.

O ASP.NET Core oferece o Middleware de Verificações de Integridade e bibliotecas para relatar a integridade de componentes de infraestrutura do aplicativo.

As verificações de integridade são expostas por um aplicativo como pontos de extremidade HTTP. Os pontos de extremidade de verificação de integridade podem ser configurados para vários cenários de monitoramento em tempo real:

  • As investigações de integridade podem ser usadas por orquestradores de contêineres e balanceadores de carga para verificar o status de um aplicativo. Por exemplo, um orquestrador de contêineres pode responder a uma verificação de integridade com falha interrompendo uma implantação sem interrupção ou reiniciando um contêiner. Um balanceador de carga pode reagir a um aplicativo não íntegro encaminhando o tráfego para fora da instância com falha para uma instância íntegra.
  • O uso de memória, disco e outros recursos de servidor físico pode ser monitorado quanto ao status de integridade.
  • As verificações de integridade podem testar as dependências do aplicativo, como bancos de dados e pontos de extremidade de serviço externo, para confirmar a disponibilidade e o funcionamento normal.

As verificações de integridade são normalmente usadas com um orquestrador de contêineres ou um serviço de monitoramento externo para verificar o status de um aplicativo. Antes de adicionar verificações de integridade a um aplicativo, decida qual sistema de monitoramento será usado. O sistema de monitoramento determina quais tipos de verificações de integridade serão criados e como configurar seus pontos de extremidade.

Investigação de integridade básica

Para muitos aplicativos, uma configuração básica de investigação de integridade que relata a disponibilidade do aplicativo para processar solicitações (atividade) é suficiente para descobrir o status do aplicativo.

A configuração básica registra os serviços de verificação de integridade e chama o Middleware de Verificações de Integridade para responder a um ponto de extremidade de URL com uma resposta de integridade. Por padrão, nenhuma verificação de integridade específica é registrada para testar qualquer dependência ou subsistema específico. O aplicativo é considerado íntegro se consegue responder na URL do ponto de extremidade de integridade. O gravador de resposta padrão grava HealthStatus como uma resposta de texto sem formatação para o cliente. O HealthStatus é HealthStatus.Healthy, HealthStatus.Degradedou HealthStatus.Unhealthy.

Registre os serviços de verificação de integridade com AddHealthChecks em Program.cs. Crie um ponto de extremidade de verificação de integridade chamando MapHealthChecks.

O exemplo a seguir cria um ponto de extremidade de verificação de integridade em /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

O Docker oferece uma diretiva HEALTHCHECK interna que pode ser usada para verificar o status de um aplicativo que usa a configuração básica de verificação de integridade:

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

O exemplo anterior usa curl para fazer uma solicitação HTTP para o ponto de extremidade de verificação de integridade em /healthz. curl não está incluído nas imagens de contêiner do .NET Linux, mas pode ser adicionado instalando o pacote necessário no Dockerfile. Os contêineres que usam imagens com base no Alpine Linux podem usar o wget incluído ao invés de curl.

Criar verificações de integridade

As verificações de integridade são criadas pela implementação da interface IHealthCheck. O método CheckHealthAsync retorna um HealthCheckResult que indica a integridade como Healthy, Degraded ou Unhealthy. O resultado é gravado como uma resposta de texto sem formatação com um código de status configurável. A configuração é descrita na seção Opções de verificação de integridade. HealthCheckResult também pode retornar pares chave-valor opcionais.

O exemplo a seguir demonstra o layout de uma verificação de integridade:

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

A lógica da verificação de integridade é colocada no método CheckHealthAsync. O exemplo anterior define uma variável fictícia, isHealthy, como true. Se o valor de isHealthy for definido como false, o status de HealthCheckRegistration.FailureStatus será retornado.

Se CheckHealthAsync gerar uma exceção durante a verificação, um novo HealthReportEntry será retornado com seu HealthReportEntry.Status definido como FailureStatus. Esse status é definido por AddCheck (consulte a seção Registrar serviços de verificação de integridade) e inclui a exceção interna que causou a falha de verificação. O Description é definido como a mensagem da exceção.

Registrar os serviços de verificação de integridade

Para registrar um serviço de verificação de integridade, chame AddCheck em Program.cs:

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

A sobrecarga AddCheck mostrada no exemplo a seguir define o status de falha (HealthStatus) como relatório quando a verificação de integridade relata uma falha. Se o status de falha é definido como null (padrão), HealthStatus.Unhealthy é relatado. Essa sobrecarga é um cenário útil para autores de biblioteca, em que o status de falha indicado pela biblioteca é imposto pelo aplicativo quando uma falha de verificação de integridade ocorre se a implementação da verificação de integridade respeita a configuração.

Marcações podem ser usadas para filtrar verificações de integridade. As marcações são descritas na seção Filtrar verificações de integridade.

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

AddCheck também pode executar uma função lambda. No exemplo a seguir, a verificação de integridade sempre retorna um resultado íntegro:

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

Chame AddTypeActivatedCheck para aprovar argumentos para uma implementação de verificação de integridade. No exemplo a seguir, uma verificação de integridade ativada por tipo aceita um inteiro e uma cadeia de caracteres em seu construtor:

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 a verificação de integridade anterior, chame AddTypeActivatedCheck com o inteiro e a cadeia de caracteres aprovados como argumentos:

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

Usar roteamento de verificações de integridade

No Program.cs, chame MapHealthChecks no construtor de ponto de extremidade com a URL de ponto de extremidade ou o caminho relativo:

app.MapHealthChecks("/healthz");

Exigir host

Chame RequireHost para especificar um ou mais hosts permitidos para o ponto de extremidade de verificação de integridade. Os hosts devem ser Unicode em vez de punycode e podem incluir uma porta. Se uma coleção não for fornecida, qualquer host será aceito:

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

Para restringir o ponto de extremidade de verificação de integridade para responder somente em uma determinada porta, especifique uma porta na chamada para RequireHost. Essa abordagem normalmente é usada em um ambiente de contêiner para expor uma porta para os serviços de monitoramento:

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

Aviso

Uma API que dependa do cabeçalho de host, como HttpRequest.Host e RequireHost, está sujeita a possíveis falsificações por clientes.

Para evitar falsificação de host e porta, use uma das seguintes abordagens:

Para impedir que clientes não autorizados falsifiquem a porta, chame RequireAuthorization:

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

Para obter mais informações, consulte Correspondência de host em rotas com RequireHost.

Exigir autorização

Chame RequireAuthorization para executar o Middleware de autorização no ponto de extremidade da solicitação de verificação de integridade. Uma sobrecarga RequireAuthorization aceita uma ou mais políticas de autorização. Se uma política não for fornecida, a política de autorização padrão será usada:

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

Habilitar o CORS (Solicitações Entre Origens)

Embora a execução manual das verificações de integridade de um navegador não seja um cenário comum, o Middleware CORS pode ser habilitado chamando RequireCors nos pontos de extremidade das verificações de integridade. A sobrecarga RequireCors aceita um representante do construtor de políticas CORS (CorsPolicyBuilder) ou um nome de política. Para obter mais informações, consulte Habilitar solicitações entre origens (CORS, na sigla em inglês) no ASP.NET Core.

Opções de verificação de integridade

HealthCheckOptions oferece uma oportunidade de personalizar o comportamento de verificação de integridade:

Filtrar verificações de integridade

Por padrão, o Middleware de verificações de integridade executa todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que retorne um booliano para a opção Predicate.

O exemplo a seguir filtra as verificações de integridade para que somente aquelas marcadas com sample sejam executadas:

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

Personalizar o código de status HTTP

Use ResultStatusCodes para personalizar o mapeamento de status da integridade para códigos de status HTTP. As atribuições StatusCodes a seguir são os valores padrão usados pelo middleware. Altere os valores do código de status de acordo com suas necessidades:

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

Suprimir os cabeçalhos de cache

AllowCachingResponses controla se o Middleware de verificações de integridade adiciona cabeçalhos HTTP a uma resposta de investigação para prevenir o cache de resposta. Se o valor é false (padrão), o middleware define ou substitui os cabeçalhos Cache-Control, Expires e Pragma para prevenir o cache de resposta. Se o valor for true, o middleware não modifica os cabeçalhos de cache da resposta:

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

Personalizar a saída

Para personalizar a saída de um relatório de verificações de integridade, defina a propriedade HealthCheckOptions.ResponseWriter como um representante que grava a resposta:

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

O representante padrão grava uma resposta mínima de texto sem formatação com o valor de cadeia de caracteres HealthReport.Status. O representante personalizado a seguir gera uma JSresposta ON personalizada usando 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()));
}

A API de verificações de integridade não fornece suporte interno para formatos de retorno JSON complexos porque o formato é específico para sua escolha de sistema de monitoramento. Personalize a resposta nos exemplos anteriores, conforme necessário. Para obter mais informações sobre a serialização JSON com System.Text.Json, consulte Como serializar e desserializar JSON no .NET.

Investigação de banco de dados

Uma verificação de integridade pode especificar uma consulta de banco de dados a ser executada como um teste booliano para indicar se o banco de dados está respondendo normalmente.

AspNetCore.Diagnostics.HealthChecks, uma biblioteca de verificação de integridade para aplicativos do ASP.NET Core, inclui uma verificação de integridade executada em um banco de dados do SQL Server. O AspNetCore.Diagnostics.HealthChecks executa uma consulta SELECT 1 no banco de dados para confirmar se a conexão ao banco de dados está íntegra.

Aviso

Ao verificar uma conexão de banco de dados com uma consulta, escolha uma consulta que retorne rapidamente. A abordagem de consulta corre o risco de sobrecarregar o banco de dados e prejudicar o desempenho. Na maioria dos casos, a execução de uma consulta de teste não é necessária. É suficiente apenas estabelecer uma conexão bem-sucedida ao banco de dados. Se você achar necessário executar uma consulta, escolha uma consulta SELECT simples, como SELECT 1.

Para usar essa verificação de integridade do SQL Server, inclua uma referência de pacote ao pacote AspNetCore.HealthChecks.SqlServer NuGet. O exemplo a seguir registra a verificação de integridade do SQL Server:

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

Observação

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Investigação de DbContext do Entity Framework Core

A verificação DbContext confirma se o aplicativo pode se comunicar com o banco de dados configurado para um EF CoreDbContext. A verificação DbContext é compatível em aplicativos que:

AddDbContextCheck registra uma verificação de integridade para um DbContext. O DbContext é fornecido ao método como o TContext. Uma sobrecarga está disponível para configurar o status de falha, marcas e uma consulta de teste personalizada.

Por padrão:

  • O DbContextHealthCheck chama o método CanConnectAsync do EF Core. Você pode personalizar qual operação é executada durante a verificação de integridade usando sobrecargas do método AddDbContextCheck.
  • O nome da verificação de integridade é o nome do tipo TContext.

O exemplo a seguir registra um DbContext e um DbContextHealthCheck associado:

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

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

Investigações de preparação e atividade separadas

Em alguns cenários de hospedagem, é usado um par de verificações de integridade que distingue dois estados de aplicativo:

  • Preparação indica se o aplicativo está em execução normalmente, mas não está pronto para receber solicitações.
  • Atividade indica se um aplicativo falhou e deve ser reiniciado.

Considere o exemplo a seguir: um aplicativo deve baixar um arquivo de configuração grande antes de estar pronto para processar solicitações. Não queremos que o aplicativo seja reiniciado se o download inicial falhar porque o aplicativo pode tentar baixar o arquivo novamente várias vezes. Usamos uma investigação de atividade para descrever a atividade do processo; nenhuma outra verificação é executada. Também queremos impedir que as solicitações sejam enviadas ao aplicativo antes que o download do arquivo de configuração seja bem-sucedido. Usamos uma investigação de preparação para indicar um estado "não pronto" até que o download seja bem-sucedido e o aplicativo esteja pronto para receber solicitações.

A tarefa em segundo plano a seguir simula um processo de inicialização que leva cerca de 15 segundos. Depois de concluída, a tarefa define a propriedade StartupHealthCheck.StartupCompleted como 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;
    }
}

O StartupHealthCheck relata a conclusão da tarefa de inicialização de execução prolongada e expõe a propriedade StartupCompleted que é definida pelo serviço em 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."));
    }
}

A verificação de integridade é registrada em AddCheck no Program.cs juntamente com o serviço hospedado. Como o serviço hospedado precisa definir a propriedade na verificação de integridade, a verificação de integridade também é registrada no contêiner de serviço como um banco de dados individual:

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

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

Para criar dois pontos de extremidade de verificação de integridade diferentes, chame MapHealthChecks duas vezes:

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

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

O exemplo anterior cria os seguintes pontos de extremidade de verificação de integridade:

  • /healthz/ready para a verificação de preparação. A verificação de preparação filtra as verificações de integridade para aquelas marcadas com ready.
  • /healthz/live para a verificação de atividade. A verificação de atividade filtra todas as verificações de integridade retornando false no representante HealthCheckOptions.Predicate. Para obter mais informações sobre como filtrar verificações de integridade, consulte Filtrar verificações de integridade neste artigo.

Antes da conclusão da tarefa de inicialização, o ponto de extremidade /healthz/ready relata um status Unhealthy. Depois que a tarefa de inicialização for concluída, esse ponto de extremidade relatará um status Healthy. O ponto de extremidade /healthz/live exclui todas as verificações e relata um status Healthy para todas as chamadas.

Exemplo do Kubernetes

O uso de verificações de preparação e atividade separadas é útil em um ambiente como o Kubernetes. No Kubernetes, um aplicativo pode precisar executar um trabalho de inicialização demorado antes de aceitar solicitações, como um teste da disponibilidade do banco de dados subjacente. O uso de verificações separadas permite que o orquestrador distinga se o aplicativo está funcionando, mas ainda não está pronto, ou se o aplicativo falhou ao ser iniciado. Para obter mais informações sobre as investigações de preparação e atividade no Kubernetes, confira Configurar investigações de preparação e atividade na documentação do Kubernetes.

O seguinte exemplo demonstra uma configuração de investigação de preparação do 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

Distribuir uma biblioteca de verificação de integridade

Para distribuir uma verificação de integridade como uma biblioteca:

  1. Escreva uma verificação de integridade que implementa a interface IHealthCheck como uma classe autônoma. A classe pode depender da DI (injeção de dependência), da ativação de tipo e das opções nomeadas para acessar os dados de configuração.

  2. Escreva um método de extensão com parâmetros que o aplicativo de consumo chama em seu método Program.cs. Considere o exemplo a seguir de verificação de integridade, que aceita arg1 e arg2 como parâmetros de construtor:

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

    A assinatura anterior indica que a verificação de integridade exige dados personalizados para processar a lógica de investigação da verificação de integridade. Os dados são fornecidos para o representante usado para criar a instância de verificação de integridade quando a verificação de integridade é registrada em um método de extensão. No exemplo a seguir, o chamador especifica:

    • arg1: um ponto de dados de inteiro para a verificação de integridade.
    • arg2: um argumento de cadeia de caracteres para a verificação de integridade.
    • name: um nome de verificação de integridade opcional. Se null, o valor padrão é usado.
    • failureStatus: um HealthStatus opcional, que é relatado para um status de falha. Se null, HealthStatus.Unhealthy é usado.
    • tags: uma coleção IEnumerable<string> opcional de marcações.
    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 Verificação de Integridade

Quando um IHealthCheckPublisher é adicionado ao contêiner de serviços, o sistema de verificação de integridade periodicamente executa sua verificação de integridade e chama PublishAsync com o resultado. Esse processo é útil em um cenário de sistema de monitoramento de integridade baseado em push que espera que cada processo chame o sistema de monitoramento periodicamente para determinar a integridade.

HealthCheckPublisherOptions permite que você defina:

  • Delay: o atraso inicial aplicado após o aplicativo começar antes de executar instâncias IHealthCheckPublisher. O atraso é aplicado uma vez na inicialização e não ocorre em iterações posteriores. O valor padrão é cinco segundos.
  • Period: o período da execução de IHealthCheckPublisher. O valor padrão é 30 segundos.
  • Predicate: se Predicate for null (padrão), o serviço do publicador de verificação de integridade executará todas as verificações de integridade registradas. Para executar um subconjunto das verificações de integridade, forneça uma função que filtre o conjunto de verificações. O predicado é avaliado a cada período.
  • Timeout: o tempo limite para a execução de verificações de integridade em todas as instâncias IHealthCheckPublisher. Use InfiniteTimeSpan para executar sem um tempo limite. O valor padrão é 30 segundos.

O exemplo a seguir demonstra o layout de um publicador de integridade:

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

        return Task.CompletedTask;
    }
}

A classe HealthCheckPublisherOptions fornece propriedades para configurar o comportamento do publicador de verificação de integridade.

O exemplo a seguir registra um publicador de verificação de integridade como um banco de dados individual e configura HealthCheckPublisherOptions:

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

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

Observação

O AspNetCore.Diagnostics.HealthChecks inclui publicadores para vários sistemas, incluindo o Application Insights.

O AspNetCore.Diagnostics.HealthChecks não é mantido nem tem suporte da Microsoft.

Injeção de dependência e verificações de integridade

É possível usar a injeção de dependência para consumir uma instância de um Type específico dentro de uma classe de Verificação de Integridade. A injeção de dependência pode ser útil para injetar opções ou uma configuração global em uma Verificação de Integridade. O uso da injeção de dependência não é um cenário comum para configurar verificações de integridade. Normalmente, cada Verificação de Integridade é bastante específica para o teste real e é configurada usando métodos de extensão IHealthChecksBuilder.

O exemplo a seguir exibe uma amostra de Verificação de Integridade que recupera um objeto de configuração por meio da injeção de dependência:

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

O SampleHealthCheckWithDiConfig e a verificação de integridade precisam ser adicionados ao contêiner de serviço :

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 vs. MapHealthChecks

Há duas maneiras de tornar as verificações de integridade acessíveis aos chamadores:

  • UseHealthChecks registra o middleware para lidar com solicitações de verificação de integridade no pipeline de middleware.
  • MapHealthChecks registra um ponto de extremidade de verificação de integridade. O ponto de extremidade é correspondido e executado junto com outros pontos de extremidade no aplicativo.

A vantagem de usar MapHealthChecks em vez de UseHealthChecks é a capacidade de usar middleware com reconhecimento de ponto de extremidade, como uma autorização, e ter maior controle refinado sobre a política de correspondência. A principal vantagem de usar UseHealthChecks em vez de MapHealthChecks é controlar exatamente onde as verificações de integridade são executadas no pipeline do middleware.

UseHealthChecks:

  • Encerra o pipeline quando uma solicitação corresponde ao ponto de extremidade de verificação de integridade. O curto-circuito geralmente é desejável porque evita trabalhos desnecessários, como registro em log e outro middleware.
  • É usado principalmente para configurar o middleware de verificação de integridade no pipeline.
  • Pode corresponder qualquer caminho em uma porta com um null ou PathString vazio. Permite executar uma verificação de integridade em qualquer solicitação feita à porta especificada.
  • Código-fonte

MapHealthChecks permite:

  • Mapear rotas ou pontos de extremidade específicos para verificações de integridade.
  • Personalizar o URL ou caminho em que o ponto de extremidade de verificação de integridade está acessível.
  • Mapear vários pontos de extremidade de verificação de integridade com diferentes rotas ou configurações. Suporte a vários pontos de extremidade:
    • Habilita pontos de extremidade separados para diferentes tipos de verificações de integridade ou componentes.
    • É usado para diferenciar entre aspectos distintos da integridade do aplicativo ou aplicar configurações específicas a subconjuntos de verificações de integridade.
  • Código-fonte

Recursos adicionais

Observação

Este artigo foi parcialmente criado com a ajuda de inteligência artificial. Antes de publicar, um autor revisou o conteúdo conforme necessário. Consulte Nossos princípios para usar conteúdo gerado por IA no Microsoft Learn.