Поделиться через


Проверки работоспособности в ASP.NET Core

Гленн Кондрон и Джуерген Гутш

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

ASP.NET Core предоставляет ПО промежуточного слоя и библиотеки для создания отчетов о работоспособности компонентов инфраструктуры приложения.

Проверки работоспособности предоставляются приложением как конечные точки HTTP. Конечные точки проверки работоспособности можно настроить для различных сценариев мониторинга в реальном времени:

  • Проверки работоспособности можно использовать с оркестраторами контейнеров и подсистемами балансировки нагрузки, чтобы проверять состояние приложения. Например, оркестратор контейнеров может реагировать на неуспешную проверку работоспособности, остановив последовательное развертывание или перезапустив контейнер. Балансировщик нагрузки может реагировать на неработоспособное приложение путем перенаправления трафика от неисправного экземпляра к работающему экземпляру.
  • Использование памяти, диска и других ресурсов физического сервера можно отслеживать с точки зрения работоспособности.
  • Проверки работоспособности позволяют проверять зависимости приложения, такие как базы данных и конечные точки внешних служб, чтобы убедиться в доступности и нормальной работе.

Проверки работоспособности обычно используются в оркестраторе контейнеров или внешней службе мониторинга для проверки состояния приложения. Перед добавлением проверки работоспособности приложения выберите используемую систему мониторинга. Система мониторинга определяет, какие виды проверки работоспособности создавать и как настроить их конечные точки.

Базовая проверка работоспособности

Для многих приложений достаточно конфигурации базовой проверки работоспособности, которая сообщает о доступности приложения для обработки запросов (жизнеспособности).

Базовая конфигурация регистрирует службы проверки работоспособности и вызывает ПО промежуточного слоя для получения ответа о работоспособности в конечной точке по URL-адресу. По умолчанию отдельные проверки работоспособности не регистрируются для тестирования какой-либо конкретной зависимости или подсистемы. Приложение считается работоспособным, если оно способно отвечать на запросы по URL-адресу конечной точки работоспособности. Модуль записи ответа по умолчанию записывает HealthStatus в качестве ответа клиенту в виде простого текста. Значение HealthStatus равно HealthStatus.Healthy, HealthStatus.Degraded или HealthStatus.Unhealthy.

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Program.cs. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks.

В примере ниже создается конечная точка проверки работоспособности в /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker предлагает встроенную директиву HEALTHCHECK, которую можно вызвать для проверки состояния приложения, использующего базовую конфигурацию проверки работоспособности:

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

В предыдущем примере используется curl, чтобы выполнить HTTP-запрос к конечной точке проверки работоспособности по адресу /healthz. curl не входит в образы контейнеров .NET Linux, но его можно добавить, установив необходимый пакет в Dockerfile. Контейнеры, использующие образы на основе Alpine Linux, могут использовать включенный wget вместо curl.

Создание проверки работоспособности

Проверки работоспособности создаются путем реализации интерфейса IHealthCheck. Метод CheckHealthAsync возвращает HealthCheckResult, что означает состояние работоспособности Healthy, Degraded или Unhealthy. Результат записывается как ответ в виде простого текста с настраиваемым кодом состояния. Конфигурация описана в разделе Параметры проверки работоспособности. HealthCheckResult также может возвращать необязательные пары "ключ-значение".

Следующий пример демонстрирует структуру процесса проверки работоспособности:

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

Логика проверки работоспособности помещается в метод CheckHealthAsync. В предыдущем примере для фиктивной переменной isHealthy задается значение true. Если isHealthy задано значение false, возвращается состояние HealthCheckRegistration.FailureStatus.

Если CheckHealthAsync вызывает исключение во время проверки, возвращается новый объект HealthReportEntry, у которого HealthReportEntry.Status равняется FailureStatus. Это состояние определяется AddCheck (см. раздел Зарегистрируйте службы проверки работоспособности) и включает внутреннее исключение, вызвавшее сбой проверки. Для сообщения исключения задается свойство Description.

Зарегистрируйте службы проверки работоспособности

Чтобы зарегистрировать службу проверки работоспособности, вызовите AddCheck в Program.cs:

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

Перегрузка AddCheck, показанная в следующем примере, устанавливает состояние сбоя (HealthStatus) для отчета в ситуации, когда проверка работоспособности сообщает о сбое. Если присвоено состояние сбоя null (по умолчанию), сообщается HealthStatus.Unhealthy. Эта перегрузка — полезный сценарий для авторов библиотек, где состояние сбоя от библиотеки особо учитывается приложением при сбое проверки работоспособности, если реализация проверки работоспособности учитывает этот параметр.

Теги можно использовать для фильтрации проверок работоспособности. Теги описаны в разделе Фильтрация проверок работоспособности.

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

AddCheck также может выполнять лямбда-функции. В следующем примере проверка работоспособности всегда возвращает работоспособное состояние:

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

Вызовите AddTypeActivatedCheck, чтобы передать аргументы реализации проверки работоспособности. В следующем примере проверка работоспособности, активируемая с помощью типа, принимает целое число и строку в своем конструкторе:

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

Чтобы зарегистрировать предыдущую проверку работоспособности, вызовите метод AddTypeActivatedCheck, передав целое число и строку в качестве аргументов:

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

Использование маршрутизации при проверках работоспособности

В Program.cs вызовите MapHealthChecks для построителя конечной точки с URL-адресом конечной точки или относительным путем:

app.MapHealthChecks("/healthz");

RequireHost

Вызовите RequireHost, чтобы указать один или несколько разрешенных узлов для конечной точки проверки работоспособности. Узлы должны быть указаны в Юникоде, а не Punycode, и могут включать порт. Если коллекция не указана, допускается любой узел:

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

Чтобы ограничить конечную точку проверки работоспособности, чтобы она отвечала только на конкретный порт, укажите порт в вызове RequireHost. Обычно этот подход используется в контейнерной среде с целью предоставления порта для мониторинга служб:

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

Предупреждение

API, основанный на заголовке узла, например HttpRequest.Host и RequireHost, подвержены потенциальному спуфинду клиентов.

Чтобы предотвратить спуфинирование узлов и портов, используйте один из следующих подходов:

Чтобы запретить несанкционированным клиентам спуфинировать порт, вызовите следующую команду RequireAuthorization:

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

Дополнительные сведения см. в статье Сопоставление узлов в маршрутах с помощью RequireHost.

RequireAuthorization

Вызовите RequireAuthorization для запуска ПО промежуточного слоя для авторизации в конечной точке запроса проверки работоспособности. Перегрузка RequireAuthorization принимает одну или несколько политик авторизации. Если политика не указана, используется политика авторизации по умолчанию:

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

Включение запросов о происхождении (CORS)

Хотя выполнение проверок работоспособности вручную из браузера — не распространенный сценарий, можно включить ПО промежуточного слоя CORS, вызывая RequireCors в конечных точках проверки работоспособности. Перегрузка RequireCors принимает делегат построителя политики CORS (CorsPolicyBuilder) или имя политики. Дополнительные сведения см. в статье Включение запросов CORS в ASP.NET Core.

Варианты проверки работоспособности

HealthCheckOptions предоставляет возможность настройки поведения для проверки работоспособности:

Фильтрация проверок работоспособности

По умолчанию ПО промежуточного слоя для проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить подмножество проверок работоспособности, укажите функцию, которая возвращает логическое значение через параметр Predicate.

В следующем примере выполняется фильтрация проверок работоспособности, чтобы запускались только те, у которых есть тег sample:

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

Настройка кода состояния HTTP

Используйте ResultStatusCodes для настройки сопоставления состояний работоспособности и кодов состояния HTTP. Следующие назначения StatusCodes являются значениями по умолчанию, используемыми ПО промежуточного слоя. Измените значения кодов состояния в соответствии с требованиями:

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

Подавление заголовков кэша

AllowCachingResponses определяет, добавляет ли ПО промежуточного слоя HTTP-заголовки в ответ проверки, чтобы предотвратить кэширование ответов. Если значение равно false (по умолчанию), ПО промежуточного слоя задает или переопределяет заголовки Cache-Control, Expires и Pragma, чтобы предотвратить кэширование ответов. Если значение равно true, ПО промежуточного слоя не изменяет заголовки кэша в ответе:

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

Настройка выходных данных

Чтобы настроить вывод отчета о проверках работоспособности, присвойте свойству HealthCheckOptions.ResponseWriter делегат, записывающий ответ:

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

Делегат по умолчанию записывает минимальный ответ в виде открытого текста со строковым значением HealthReport.Status. Следующий пользовательский делегат выводит настраиваемый ответ JSON с помощью 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()));
}

API проверки работоспособности не предоставляет встроенной поддержки сложных форматов возврата JSON, так как формат зависит от выбранной системы мониторинга. При необходимости настройте ответ в предыдущих примерах. Дополнительные сведения о сериализации JSON с System.Text.Json см. в статье о сериализации и десериализации JSON в .NET.

Проверка базы данных

Проверка работоспособности может задать запрос для выполнения в качестве логического теста для указания того, отвечает ли база данных как обычно.

AspNetCore.Diagnostics.HealthChecks, библиотека проверки работоспособности для приложений ASP.NET Core включает проверку работоспособности, которая выполняется для базы данных SQL Server. AspNetCore.Diagnostics.HealthChecks выполняет запрос SELECT 1 к базе данных, чтобы подтвердить, что подключение к базе данных находится в работоспособном состоянии.

Предупреждение

При проверке подключения к базе данных с помощью запроса выберите запрос, возвращающий результат быстро. Метод запроса связан с риском перегрузки базы данных и снижения ее производительности. В большинстве случаев тестовый запрос не является обязательным. Достаточно успешного подключения к базе данных. Если вам понадобится выполнить запрос, выберите простой запрос SELECT, например SELECT 1.

Чтобы использовать эту проверку работоспособности SQL Server, включите ссылку на пакет NuGet AspNetCore.HealthChecks.SqlServer. В следующем примере регистрируется проверка работоспособности 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);

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Проверка DbContext в Entity Framework Core

Проверка DbContext подтверждает, что приложение может взаимодействовать с базой данных, настроенной EF CoreDbContextдля объекта. Проверка DbContext поддерживается в приложениях, которые:

AddDbContextCheck регистрирует проверку работоспособности для DbContext. DbContext передается методу в качестве TContext. Доступна перегрузка, позволяющая настроить состояние ошибки, теги и запрос тестирования.

По умолчанию:

  • Метод DbContextHealthCheck вызоваEF CoreCanConnectAsync. Вы можете указать, какая операция выполняется в том случае, когда проверка работоспособности производится с помощью перегрузок метода AddDbContextCheck.
  • Имя проверки работоспособности — это имя типа TContext.

В следующем примере показано, как зарегистрировать DbContext и связанный объект DbContextHealthCheck:

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

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

Разделение проверок готовности и активности

В некоторых сценариях размещения используется пара проверок работоспособности, отличающая два состояния приложения:

  • Готовность указывает, что приложение работает нормально, но не готово к приему запросов.
  • Активность указывает на сбой приложения, и его необходимо перезапустить.

Рассмотрим следующий пример: приложение должно скачать большой файл конфигурации, прежде чем он готов к обработке запросов. Нам не требуется перезапуск приложения в случае сбоя начальной загрузки, так как приложение может повторить попытку скачивания файла несколько раз. Для описания активности процесса используется проба активности, дополнительные проверки не выполняются. Кроме того, мы хотим предотвратить отправку запросов в приложение до успешной загрузки файла конфигурации. Мы используем пробу активности, чтобы указать состояние "не готово" до тех пор, пока загрузка не будет завершена и приложение не сможет принимать запросы.

Следующая фоновая задача имитирует процесс запуска, который занимает примерно 15 секунд. После завершения задача устанавливает для свойства StartupHealthCheck.StartupCompleted значение true:

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

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

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

        _healthCheck.StartupCompleted = true;
    }
}

StartupHealthCheck сообщает о завершении длительной задачи запуска и предоставляет свойство StartupCompleted, которое задается фоновой службой:

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

Проверка работоспособности регистрируется через AddCheck в Program.cs вместе с размещенной службой. Поскольку размещенной службе необходимо задать свойство проверки работоспособности, проверка работоспособности также регистрируется в контейнере службы как singleton:

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

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

Чтобы создать две разные конечные точки проверки работоспособности, вызовите MapHealthChecks два раза:

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

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

В предыдущем примере создаются приведенные ниже конечные точки проверки работоспособности:

  • В /healthz/ready для проверки готовности. Проверка готовности фильтрует проверки работоспособности, оставляя те, которые помечены ready.
  • В /healthz/live для проверки жизнеспособности. Проверка активности отфильтровывает все проверки работоспособности, возвращая false в делегат HealthCheckOptions.Predicate. Дополнительные сведения о фильтрации проверок работоспособности см. в разделе Фильтрация проверок работоспособности в этой статье.

Перед завершением задачи запуска конечная точка /healthz/ready сообщает о состоянии Unhealthy. После завершения задачи запуска эта конечная точка сообщает о состоянии Healthy. Конечная точка /healthz/live исключает все проверки и сообщает о состоянии Healthy всех вызовов.

Пример для Kubernetes

Использование отдельных проверок готовности и жизнеспособности полезно в таких средах, как Kubernetes. В Kubernetes приложениям может потребоваться долго выполнять задачи во время запуска, прежде чем начать принимать запросы; например, проверить доступность основной базы данных. Использование отдельных проверок позволяет оркестратору различать, когда приложение работает, но еще не готово, а когда приложение не удалось запустить. Дополнительные сведения о проверках готовности и жизнеспособности в Kubernetes см. в разделе Настройка проверок готовности и жизнеспособности в документации по Kubernetes.

В следующем примере показана конфигурация проверки готовности для 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

Распространение библиотеки проверки работоспособности

Чтобы распространять проверки работоспособности в качестве библиотеки, выполните следующие действия.

  1. Напишите проверку работоспособности, которая реализует интерфейс IHealthCheck как автономный класс. Класс может полагаться на внедрение зависимостей (DI), активацию типов и именованные параметры для доступа к данным конфигурации.

  2. Напишите метод расширения с параметрами, который приложение вызывает в своем методе Program.cs. Рассмотрим следующий пример проверки работоспособности, который принимает arg1 и arg2 в качестве параметров конструктора:

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

    Эта сигнатура указывает, что проверке работоспособности требуются пользовательские данные для обработки логики проверки работоспособности. Данные передаются делегату, используемому для создания экземпляра проверки работоспособности, когда проверка работоспособности регистрируется с помощью метода расширения. В следующем примере вызывающая сторона задает:

    • arg1 — целочисленная точка данных для проверки работоспособности.
    • arg2 — строковый аргумент для проверки работоспособности.
    • name — необязательное имя проверки работоспособности. При null используется значение по умолчанию.
    • failureStatus — необязательные HealthStatus, который передается в случае состояния неполадки. Если null, используется HealthStatus.Unhealthy.
    • tags — необязательная коллекция тегов IEnumerable<string>.
    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));
        }
    }
    

Издатель проверки работоспособности

Когда IHealthCheckPublisher добавляется в контейнер службы, система проверки работоспособности периодически выполняет ваши проверки работоспособности и вызывает PublishAsync с полученным результатом. Этот процесс полезен в ситуации принудительной передачи данных мониторинга работоспособности, когда ожидается, что каждый процесс периодически вызывает систему мониторинга для определения работоспособности.

HealthCheckPublisherOptions позволяет задать следующие параметры:

  • Delay: начальная задержка, примененная после запуска приложения перед выполнением IHealthCheckPublisher экземпляров. Задержка применяется при запуске один раз и не распространяется на все последующие итерации. Значение по умолчанию — пять секунд.
  • Period: период IHealthCheckPublisher выполнения. Значение по умолчанию — 30 секунд.
  • Predicate: если Predicate задано null (по умолчанию), служба издателя проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить ряд проверок работоспособности, укажите функцию, которая отфильтровывает нужный набор. Предикат вычисляется в каждом периоде.
  • Timeout: время ожидания для выполнения проверок работоспособности для всех IHealthCheckPublisher экземпляров. Используйте InfiniteTimeSpan, чтобы выполнить проверки без задержки. Значение по умолчанию — 30 секунд.

Следующий пример демонстрирует структуру издателя проверки работоспособности:

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

        return Task.CompletedTask;
    }
}

Класс HealthCheckPublisherOptions предоставляет свойства для настройки поведения издателя проверки работоспособности.

В следующем примере регистрируется издатель проверки работоспособности как singleton и настраиваются 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:

  • Включает издателей для нескольких систем, включая Application Insights.
  • Не поддерживается или поддерживается корпорацией Майкрософт.

Отдельные проверки работоспособности

Delay и Period его можно задать по отдельности HealthCheckRegistration . Это полезно, если требуется выполнить некоторые проверки работоспособности по частоте, отличной от заданного периода HealthCheckPublisherOptions.

Следующий код задает и Period для SampleHealthCheck1следующих элементовDelay:

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

Внедрение зависимостей и проверка работоспособности

Можно использовать внедрение зависимостей для использования экземпляра определенного Type внутри класса проверки работоспособности. Внедрение зависимостей может быть полезно для внедрения параметров или глобальной конфигурации в проверку работоспособности. Использование внедрения зависимостей не является обычным сценарием для настройки проверок работоспособности. Обычно каждая проверка работоспособности вполне зависит от фактического теста и настраивается с помощью IHealthChecksBuilder методов расширения.

В следующем примере показан пример проверки работоспособности, который извлекает объект конфигурации с помощью внедрения зависимостей:

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

Проверка SampleHealthCheckWithDiConfig работоспособности должна быть добавлена в контейнер службы:

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

Существует два способа сделать проверки работоспособности доступными для вызывающих:

  • UseHealthChecks регистрирует ПО промежуточного слоя для обработки запросов проверки работоспособности в конвейере ПО промежуточного слоя.
  • MapHealthChecks регистрирует конечную точку проверки работоспособности. Конечная точка сопоставляется и выполняется вместе с другими конечными точками в приложении.

Преимуществом использования MapHealthChecks является UseHealthChecks возможность использовать по промежуточному слоям, поддерживающим конечные точки, например авторизацию, и более точное управление политикой сопоставления. Основным преимуществом использования UseHealthChecks является MapHealthChecks управление именно тем, где выполняются проверки работоспособности в конвейере ПО промежуточного слоя.

UseHealthChecks:

  • Завершает конвейер, когда запрос соответствует конечной точке проверки работоспособности. Короткое замыкание часто желательно, так как это позволяет избежать ненужных работ, таких как ведение журнала и другое ПО промежуточного слоя.
  • В основном используется для настройки ПО промежуточного слоя проверки работоспособности в конвейере.
  • Может совпадать с любым путем на порту или пустым null PathString. Позволяет выполнять проверку работоспособности при любом запросе, сделанном на указанный порт.
  • исходный код.

MapHealthChecks Позволяет:

  • Завершение конвейера при выполнении запроса соответствует конечной точке проверки работоспособности путем вызова ShortCircuit. Например, app.MapHealthChecks("/healthz").ShortCircuit();. Дополнительные сведения см. в разделе ПО промежуточного слоя короткого канала после маршрутизации.
  • Сопоставление определенных маршрутов или конечных точек для проверок работоспособности.
  • Настройка URL-адреса или пути, в котором доступна конечная точка проверки работоспособности.
  • Сопоставление нескольких конечных точек проверки работоспособности с различными маршрутами или конфигурациями. Поддержка нескольких конечных точек:
    • Включает отдельные конечные точки для различных типов проверок работоспособности или компонентов.
    • Используется для разных аспектов работоспособности приложения или применения определенных конфигураций к подмножествам проверок работоспособности.
  • исходный код.

Дополнительные ресурсы

Примечание.

Эта статья была частично создана с помощью искусственного интеллекта. Перед публикацией автор проверил и отредактировал содержимое по мере необходимости. См. раздел Наши принципы использования созданного ИИ содержимого в Microsoft Learn.

ASP.NET Core предоставляет ПО промежуточного слоя и библиотеки для создания отчетов о работоспособности компонентов инфраструктуры приложения.

Проверки работоспособности предоставляются приложением как конечные точки HTTP. Конечные точки проверки работоспособности можно настроить для различных сценариев мониторинга в реальном времени:

  • Проверки работоспособности можно использовать с оркестраторами контейнеров и подсистемами балансировки нагрузки, чтобы проверять состояние приложения. Например, оркестратор контейнеров может реагировать на неуспешную проверку работоспособности, остановив последовательное развертывание или перезапустив контейнер. Балансировщик нагрузки может реагировать на неработоспособное приложение путем перенаправления трафика от неисправного экземпляра к работающему экземпляру.
  • Использование памяти, диска и других ресурсов физического сервера можно отслеживать с точки зрения работоспособности.
  • Проверки работоспособности позволяют проверять зависимости приложения, такие как базы данных и конечные точки внешних служб, чтобы убедиться в доступности и нормальной работе.

Просмотреть или скачать образец кода (описание загрузки)

Пример приложения включает примеры сценариев, описанных в этой статье. Чтобы запустить пример приложения для заданного сценария, используйте команду dotnet run из папки проекта в командной строке. См. файл README.md примера приложения и описания сценариев в этой статье, чтобы получить сведения о том, как использовать пример приложения.

Необходимые компоненты

Проверки работоспособности обычно используются в оркестраторе контейнеров или внешней службе мониторинга для проверки состояния приложения. Перед добавлением проверки работоспособности приложения выберите используемую систему мониторинга. Система мониторинга определяет, какие виды проверки работоспособности создавать и как настроить их конечные точки.

Для приложений ASP.NET Core ссылка на пакет Microsoft.AspNetCore.Diagnostics.HealthChecks указывается неявно. Чтобы выполнить проверки работоспособности с помощью Entity Framework Core, добавьте ссылку на пакет Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

В примере приложения приведен код запуска для демонстрации проверки работоспособности для нескольких сценариев. Сценарий проверки базы данных проверяет работоспособность подключения к базе данных с помощью AspNetCore.Diagnostics.HealthChecks. Сценарий пробы DbContext проверяет базу данных с помощью EF CoreDbContext. Чтобы изучить сценарии для баз данных, пример приложения выполняет следующие действия.

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

В другом сценарии проверки работоспособности демонстрируется способ фильтрации проверок работоспособности по порту управления. Пример приложения требует создания Properties/launchSettings.json файла, включающего URL-адрес управления и порт управления. Дополнительные сведения см. в разделе Фильтр по портам.

Базовая проверка работоспособности

Для многих приложений достаточно конфигурации базовой проверки работоспособности, которая сообщает о доступности приложения для обработки запросов (жизнеспособности).

Базовая конфигурация регистрирует службы проверки работоспособности и вызывает ПО промежуточного слоя для получения ответа о работоспособности в конечной точке по URL-адресу. По умолчанию отдельные проверки работоспособности не регистрируются для тестирования какой-либо конкретной зависимости или подсистемы. Приложение считается работоспособным, если оно способно отвечать на запросы по URL-адресу конечной точки работоспособности. Модуль записи ответа по умолчанию записывает состояние (HealthStatus) в виде обычного текста ответа обратно клиенту; оно указывает на состояние HealthStatus.Healthy, HealthStatus.Degraded или HealthStatus.Unhealthy.

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks в Startup.Configure.

В примере приложения создается /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");
        });
    }
}

Чтобы запустить сценарий базовой конфигурации с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario basic

Пример для Docker

Docker предлагает встроенную директиву HEALTHCHECK, которую можно вызвать для проверки состояния приложения, использующего базовую конфигурацию проверки работоспособности:

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

Создание проверки работоспособности

Проверки работоспособности создаются путем реализации интерфейса IHealthCheck. Метод CheckHealthAsync возвращает HealthCheckResult, что означает состояние работоспособности Healthy, Degraded или Unhealthy. Результат записывается в ответ в виде обычного текста с кодом состояния, который можно настроить (конфигурация описана в разделе Варианты проверки работоспособности). HealthCheckResult также может возвращать необязательные пары "ключ-значение".

Следующий класс ExampleHealthCheck демонстрирует структуру процесса проверки работоспособности. Логика проверок работоспособности помещается в метод CheckHealthAsync. В следующем примере для true задается фиктивная переменная healthCheckResultHealthy. Если healthCheckResultHealthy задано значение false, возвращается состояние HealthCheckRegistration.FailureStatus.

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

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

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

Если CheckHealthAsync вызывает исключение во время проверки, возвращается новый объект HealthReportEntry, свойству HealthReportEntry.Status которого задано значение FailureStatus, определяемое методом AddCheck (см. раздел Регистрация служб проверки работоспособности) и включает внутреннее исключение, которое изначально привело к сбою проверки. Для сообщения исключения задается свойство Description.

Зарегистрируйте службы проверки работоспособности

Тип ExampleHealthCheck будет добавлен к службам проверки работоспособности с помощью AddCheck в Startup.ConfigureServices:

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

Перегрузка AddCheck, показанная в следующем примере, устанавливает состояние сбоя (HealthStatus) для отчета в ситуации, когда проверка работоспособности сообщает о сбое. Если присвоено состояние сбоя null (по умолчанию), сообщается HealthStatus.Unhealthy. Эта перегрузка — полезный сценарий для авторов библиотек, где состояние сбоя от библиотеки особо учитывается приложением при сбое проверки работоспособности, если реализация проверки работоспособности учитывает этот параметр.

Теги можно использовать для фильтрации проверок работоспособности (описаны далее в разделе Фильтрация проверок работоспособности).

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

AddCheck также может выполнять лямбда-функции. В следующем примере имя проверки работоспособности указано как Example; проверка всегда возвращает работоспособное состояние:

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

Вызовите AddTypeActivatedCheck, чтобы передать аргументы реализации проверки работоспособности. В следующем примере TestHealthCheckWithArgs принимает целое число и строку для использования при вызове CheckHealthAsync:

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

    public int I { get; set; }

    public string S { get; set; }

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

TestHealthCheckWithArgs регистрируется путем вызова AddTypeActivatedCheck с целым числом и строкой, передаваемой в реализацию:

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

Использование маршрутизации при проверках работоспособности

В Startup.Configure вызовите MapHealthChecks для построителя конечной точки с URL-адресом конечной точки или относительным путем:

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

RequireHost

Вызовите RequireHost, чтобы указать один или несколько разрешенных узлов для конечной точки проверки работоспособности. Узлы должны быть указаны в Юникоде, а не Punycode, и могут включать порт. Если коллекция не указана, допускается любой узел.

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

Дополнительные сведения см. в разделе Фильтр по портам.

RequireAuthorization

Вызовите RequireAuthorization для запуска ПО промежуточного слоя для авторизации в конечной точке запроса проверки работоспособности. Перегрузка RequireAuthorization принимает одну или несколько политик авторизации. Если политика не указана, используется политика авторизации по умолчанию.

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

Включение запросов о происхождении (CORS)

Хотя выполнение проверок работоспособности вручную из браузера не является распространенным сценарием использования, ПО промежуточного слоя CORS можно включить, вызвав RequireCors в конечных точках проверки работоспособности. Перегрузка RequireCors принимает делегат построителя политики CORS (CorsPolicyBuilder) или имя политики. Если политика не указана, используется политика CORS по умолчанию. Дополнительные сведения см. в статье Включение запросов CORS в ASP.NET Core.

Варианты проверки работоспособности

HealthCheckOptions предоставляет возможность настройки поведения для проверки работоспособности:

Фильтрация проверок работоспособности

По умолчанию ПО промежуточного слоя для проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить подмножество проверок работоспособности, укажите функцию, которая возвращает логическое значение через параметр Predicate. В следующем примере проверка работоспособности Bar отфильтровывается по тегу (bar_tag) в условном операторе функции, где true возвращается только в том случае, если свойство проверки работоспособности Tags соответствует foo_tag или baz_tag:

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

В Startup.ConfigurePredicate определяет, что проверка работоспособности Bar не выполняется. Выполняется только проверка работоспособности Foo и Baz:

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

Настройка кода состояния HTTP

Используйте ResultStatusCodes для настройки сопоставления состояний работоспособности и кодов состояния HTTP. Следующие назначения StatusCodes являются значениями по умолчанию, используемыми ПО промежуточного слоя. Измените значения кодов состояния в соответствии с требованиями.

В Startup.Configure:

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

Подавление заголовков кэша

AllowCachingResponses определяет, добавляет ли ПО промежуточного слоя HTTP-заголовки в ответ проверки, чтобы предотвратить кэширование ответов. Если значение равно false (по умолчанию), ПО промежуточного слоя задает или переопределяет заголовки Cache-Control, Expires и Pragma, чтобы предотвратить кэширование ответов. Если значение равно true, ПО промежуточного слоя не изменяет заголовки кэша в ответе.

В Startup.Configure:

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

Настройка выходных данных

В Startup.Configure задайте параметр HealthCheckOptions.ResponseWriter для делегата для записи ответа:

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

Делегат по умолчанию записывает минимальный ответ в виде открытого текста со строковым значением HealthReport.Status. Следующие пользовательские делегаты выводят настраиваемый ответ JSON.

В первом примере из примера приложения показано, как использовать 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);
    }
}

Во втором примере показано, как использовать 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));
}

В примере приложения закомментируйте директиву SYSTEM_TEXT_JSON препроцессора, CustomWriterStartup.cs чтобы включить версию .WriteResponseNewtonsoft.Json

API проверки работоспособности не предоставляет встроенной поддержки сложных форматов возврата JSON, так как формат зависит от выбранной системы мониторинга. При необходимости настройте ответ в предыдущих примерах. Дополнительные сведения о сериализации JSON с System.Text.Json см. в статье о сериализации и десериализации JSON в .NET.

Проверка базы данных

Проверка работоспособности может задать запрос для выполнения в качестве логического теста для указания того, отвечает ли база данных как обычно.

Пример приложения использует AspNetCore.Diagnostics.HealthChecks, библиотеку проверки работоспособности для приложений ASP.NET Core, чтобы проверить работоспособность базы данных SQL Server. AspNetCore.Diagnostics.HealthChecks выполняет запрос SELECT 1 к базе данных, чтобы подтвердить, что подключение к базе данных находится в работоспособном состоянии.

Предупреждение

При проверке подключения к базе данных с помощью запроса выберите запрос, возвращающий результат быстро. Метод запроса связан с риском перегрузки базы данных и снижения ее производительности. В большинстве случаев тестовый запрос не является обязательным. Достаточно успешного подключения к базе данных. Если вам понадобится выполнить запрос, выберите простой запрос SELECT, например SELECT 1.

Включите ссылку на пакет для AspNetCore.HealthChecks.SqlServer.

Укажите допустимую строку подключения к базе данных в файле примера приложения appsettings.json. Приложение использует базу данных SQL Server с именем 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": "*"
}

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Пример приложения вызывает AddSqlServer метод с строка подключения базы данных (DbHealthStartup.cs):

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure:

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

Чтобы запустить сценарий проверки базы данных с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario db

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Проверка DbContext в Entity Framework Core

Проверка DbContext подтверждает, что приложение может взаимодействовать с базой данных, настроенной EF CoreDbContextдля объекта. Проверка DbContext поддерживается в приложениях, которые:

AddDbContextCheck<TContext> регистрирует проверку работоспособности для DbContext. DbContext передается методу в качестве TContext. Доступна перегрузка, позволяющая настроить состояние ошибки, теги и запрос тестирования.

По умолчанию:

  • Метод DbContextHealthCheck вызоваEF CoreCanConnectAsync. Вы можете указать, какая операция выполняется в том случае, когда проверка работоспособности производится с помощью перегрузок метода AddDbContextCheck.
  • Имя проверки работоспособности — это имя типа TContext.

В примере приложения AppDbContext предоставляется для AddDbContextCheck и регистрируется в качестве службы в Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure:

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

Прежде чем запускать сценарий проверки DbContext с помощью примера приложения, убедитесь, что база данных, указанная в строке подключения, не существует в экземпляре SQL Server. Если база данных существует, удалите ее.

Выполните следующую команду в папке проекта в командной строке:

dotnet run --scenario dbcontext

После запуска приложения проверьте состояние работоспособности, выполнив запрос к конечной точке /health в браузере. Базы данных и AppDbContext не существуют, поэтому приложение дает следующий ответ:

Unhealthy

Заставьте пример приложения создать базу данных. Сделайте запрос к /createdatabase. Приложение выдает ответ:

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

Сделайте запрос к конечной точке /health. База данных и контекст существуют, поэтому приложение отвечает:

Healthy

Заставьте пример приложения удалить базу данных. Сделайте запрос к /deletedatabase. Приложение выдает ответ:

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

Сделайте запрос к конечной точке /health. Приложение предоставляет ответ о неработоспособности:

Unhealthy

Разделение проверок готовности и активности

В некоторых сценариях размещения используется пара проверок работоспособности, отличающая два состояния приложения:

  • Готовность указывает, что приложение работает нормально, но не готово к приему запросов.
  • Активность указывает на сбой приложения, и его необходимо перезапустить.

Рассмотрим следующий пример: приложение должно скачать большой файл конфигурации, прежде чем он готов к обработке запросов. Нам не требуется перезапуск приложения в случае сбоя начальной загрузки, так как приложение может повторить попытку скачивания файла несколько раз. Для описания активности процесса используется проба активности, дополнительные проверки не выполняются. Кроме того, мы хотим предотвратить отправку запросов в приложение до успешной загрузки файла конфигурации. Мы используем пробу активности, чтобы указать состояние "не готово" до тех пор, пока загрузка не будет завершена и приложение не сможет принимать запросы.

Пример приложения содержит проверку работоспособности, которая сообщает о завершении длительной задачи запуска размещенной службы. Предоставляет StartupHostedServiceHealthCheck свойство, StartupTaskCompletedкоторое размещенная служба может задать, true когда ее долго выполняющаяся задача (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."));
    }
}

Длительная фоновая задача запущена размещенной службой (Services/StartupHostedService). По завершении задачи StartupHostedServiceHealthCheck.StartupTaskCompleted получает значение 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()
    {
    }
}

Проверка работоспособности регистрируется через AddCheck в Startup.ConfigureServices вместе с размещенной службой. Так как размещенная служба должна задать свойство проверки работоспособности, проверка работоспособности также регистрируется в контейнере службы (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>();

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure. В примере приложения конечные точки проверки работоспособности создаются в следующих расположениях:

  • В /health/ready для проверки готовности. Проверка готовности фильтрует проверки работоспособности по тегу ready.
  • В /health/live для проверки жизнеспособности. Проверка жизнеспособности отфильтровывает StartupHostedServiceHealthCheck, возвращая false в HealthCheckOptions.Predicate (дополнительные сведения см. в разделе Фильтрация проверок работоспособности).

В следующем примере кода происходит следующее:

  • Проверка готовности использует все зарегистрированные проверки с тегом ready.
  • Predicate исключает все проверки и возвращает состояние "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
    });
}

Чтобы запустить сценарий конфигурации проверок готовности и жизнеспособности с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario liveness

В браузере посетите /health/ready несколько раз, пока не пройдет 15 секунд. Проверка работоспособности будет передавать Unhealthy первые 15 секунд. По истечении 15 секунд конечная точка передает состояние Healthy, отражающее завершение длительной задачи размещенной службой.

В этом примере также создается издатель проверки работоспособности (реализация IHealthCheckPublisher), который выполнит первую проверку готовности с задержкой в две секунды. Дополнительные сведения см. в разделе об издателе проверки работоспособности.

Пример для Kubernetes

Использование отдельных проверок готовности и жизнеспособности полезно в таких средах, как Kubernetes. В Kubernetes приложениям может потребоваться долго выполнять задачи во время запуска, прежде чем начать принимать запросы; например, проверить доступность основной базы данных. Использование отдельных проверок позволяет оркестратору различать, когда приложение работает, но еще не готово, а когда приложение не удалось запустить. Дополнительные сведения о проверках готовности и жизнеспособности в Kubernetes см. в разделе Настройка проверок готовности и жизнеспособности в документации по Kubernetes.

В следующем примере показана конфигурация проверки готовности для 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

Проба на основе метрики с настраиваемым модулем записи ответов

Этот пример демонстрирует проверку работоспособности памяти с настраиваемым модулем записи ответов.

Если приложение использует больше заданного порогового значения памяти (1 ГБ в примере приложения), MemoryHealthCheck сообщает о состоянии пониженной функциональности. Сведения HealthCheckResult о сборщике мусора (GC) для приложения (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));
    }
}

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Вместо того чтобы включать проверку работоспособности, передав ее в AddCheck, MemoryHealthCheck регистрируется в качестве службы. Все зарегистрированные службы IHealthCheck доступны в службах проверки работоспособности и ПО промежуточного слоя. Мы рекомендуем регистрировать службы проверки работоспособности в качестве одноэлементных служб.

В CustomWriterStartup.cs примере приложения:

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure. Делегат WriteResponse передается в свойство ResponseWriter для вывода настраиваемого ответа JSON при выполнении проверки работоспособности:

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

Делегат WriteResponse форматирует CompositeHealthCheckResult в объект JSON и выдает выходные данные JSON в качестве ответа проверки работоспособности. Дополнительные сведения см. в разделе Настройка выходных данных.

Чтобы запустить проверку метрики с настраиваемым модулем записи ответа с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario writer

Примечание.

AspNetCore.Diagnostics.HealthChecks включает сценарии для проверки работоспособности на основе метрик, включая проверки жизнеспособности для дискового хранилища и максимальных значений.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Фильтр по портам

Вызовите RequireHost в MapHealthChecks с шаблоном URL-адреса, в котором указан порт для ограничения запросов проверки работоспособности указанным портом. Обычно этот подход используется в контейнерной среде с целью предоставления порта для мониторинга служб.

Пример приложения настраивает порт с помощью поставщика конфигурации переменных среды. Порт задается в launchSettings.json файле и передается поставщику конфигурации через переменную среды. Необходимо также настроить на сервере прослушивание запросов через порт управления.

Чтобы использовать пример приложения для демонстрации конфигурации порта управления, создайте launchSettings.json файл в папке Properties .

Properties/launchSettings.json Следующий файл в примере приложения не включен в файлы проекта примера приложения и должен быть создан вручную:

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

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks в Startup.Configure.

В примере приложения вызов RequireHost в конечной точке в Startup.Configure указывает порт управления из конфигурации:

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

Конечные точки создаются в примере приложения в Startup.Configure. В следующем примере кода происходит следующее:

  • Проверка готовности использует все зарегистрированные проверки с тегом ready.
  • Predicate исключает все проверки и возвращает состояние "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
    });
}

Примечание.

Вы можете избежать создания launchSettings.json файла в примере приложения, задав порт управления явным образом в коде. В Program.cs месте HostBuilder создания добавьте вызов ListenAnyIP и укажите конечную точку порта управления приложения. В Configure этом ManagementPortStartup.csслучае укажите порт управления с помощью 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");
});

Чтобы запустить сценарий с портом управления с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario port

Распространение библиотеки проверки работоспособности

Чтобы распространять проверки работоспособности в качестве библиотеки, выполните следующие действия.

  1. Напишите проверку работоспособности, которая реализует интерфейс IHealthCheck как автономный класс. Класс может полагаться на внедрение зависимостей (DI), активацию типов и именованные параметры для доступа к данным конфигурации.

    Логика проверки работоспособности CheckHealthAsync предусматривает следующее:

    • Использование в методе data1 и data2 для выполнения логики проверки работоспособности.
    • Обработку AccessViolationException.

    Когда происходит AccessViolationException, FailureStatus возвращается вместе с HealthCheckResult, что позволяет пользователям настраивать состояние сбоя проверки работоспособности.

    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. Напишите метод расширения с параметрами, который приложение вызывает в своем методе Startup.Configure. В следующем примере предполагается следующая сигнатура метода проверки работоспособности:

    ExampleHealthCheck(string, string, int )
    

    Эта сигнатура указывает, что ExampleHealthCheck требуются дополнительные данные для обработки логики проверки работоспособности. Данные передаются делегату, используемому для создания экземпляра проверки работоспособности, когда проверка работоспособности регистрируется с помощью метода расширения. В следующем примере вызывающая сторона задает:

    • Необязательное имя проверки работоспособности (name). Если null, используется example_health_check.
    • Строковая точка данных для проверки работоспособности (data1).
    • Целочисленная точка данных для проверки работоспособности (data2). Если null, используется 1.
    • состояние сбоя (HealthStatus). Значение по умолчанию — null. Если null, состояние сбоя передается как HealthStatus.Unhealthy.
    • Теги (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));
        }
    }
    

Издатель проверки работоспособности

Когда IHealthCheckPublisher добавляется в контейнер службы, система проверки работоспособности периодически выполняет ваши проверки работоспособности и вызывает PublishAsync с полученным результатом. Это полезно в ситуации принудительной передачи данных мониторинга работоспособности, когда ожидается, что каждый процесс периодически вызывает систему мониторинга для определения работоспособности.

Интерфейс IHealthCheckPublisher содержит один метод:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions позволяет задать следующие параметры:

  • Delay: начальная задержка, примененная после запуска приложения перед выполнением IHealthCheckPublisher экземпляров. Задержка применяется при запуске один раз и не распространяется на все последующие итерации. Значение по умолчанию — пять секунд.
  • Period: период IHealthCheckPublisher выполнения. Значение по умолчанию — 30 секунд.
  • Predicate: если Predicate задано null (по умолчанию), служба издателя проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить ряд проверок работоспособности, укажите функцию, которая отфильтровывает нужный набор. Предикат вычисляется в каждом периоде.
  • Timeout: время ожидания для выполнения проверок работоспособности для всех IHealthCheckPublisher экземпляров. Используйте InfiniteTimeSpan, чтобы выполнить проверки без задержки. Значение по умолчанию — 30 секунд.

В примере приложения ReadinessPublisher является реализацией IHealthCheckPublisher. Состояние проверки работоспособности записывается для каждой проверки на таком уровне журнала:

  • на уровне сведений (LogInformation), если состояние проверки работоспособности — Healthy;
  • на уровне ошибки (LogError), если состояние соответствует Degraded или Unhealthy.
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;
    }
}

В примере приложения LivenessProbeStartup проверка готовности StartupHostedService использует задержку запуска в две секунды и выполняет проверку каждые 30 секунд. Чтобы активировать реализацию IHealthCheckPublisher, этот пример регистрирует ReadinessPublisher как отдельную службу в контейнере внедрения зависимостей.

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

Примечание.

AspNetCore.Diagnostics.HealthChecks включает издатели для нескольких систем, в том числе Application Insights.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Ограничение проверок работоспособности с помощью MapWhen

Используйте MapWhen для условного ветвления конвейера запросов для конечных точек проверки работоспособности.

В следующем примере MapWhen выполняет ветвление конвейера запросов для активации ПО промежуточного слоя для проверки работоспособности, если для конечной точки api/HealthCheck поступает запрос GET:

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

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

Дополнительные сведения см. в статье ПО промежуточного слоя ASP.NET Core.

ASP.NET Core предоставляет ПО промежуточного слоя и библиотеки для создания отчетов о работоспособности компонентов инфраструктуры приложения.

Проверки работоспособности предоставляются приложением как конечные точки HTTP. Конечные точки проверки работоспособности можно настроить для различных сценариев мониторинга в реальном времени:

  • Проверки работоспособности можно использовать с оркестраторами контейнеров и подсистемами балансировки нагрузки, чтобы проверять состояние приложения. Например, оркестратор контейнеров может реагировать на неуспешную проверку работоспособности, остановив последовательное развертывание или перезапустив контейнер. Балансировщик нагрузки может реагировать на неработоспособное приложение путем перенаправления трафика от неисправного экземпляра к работающему экземпляру.
  • Использование памяти, диска и других ресурсов физического сервера можно отслеживать с точки зрения работоспособности.
  • Проверки работоспособности позволяют проверять зависимости приложения, такие как базы данных и конечные точки внешних служб, чтобы убедиться в доступности и нормальной работе.

Просмотреть или скачать образец кода (описание загрузки)

Пример приложения включает примеры сценариев, описанных в этой статье. Чтобы запустить пример приложения для заданного сценария, используйте команду dotnet run из папки проекта в командной строке. См. файл README.md примера приложения и описания сценариев в этой статье, чтобы получить сведения о том, как использовать пример приложения.

Необходимые компоненты

Проверки работоспособности обычно используются в оркестраторе контейнеров или внешней службе мониторинга для проверки состояния приложения. Перед добавлением проверки работоспособности приложения выберите используемую систему мониторинга. Система мониторинга определяет, какие виды проверки работоспособности создавать и как настроить их конечные точки.

Для приложений ASP.NET Core ссылка на пакет Microsoft.AspNetCore.Diagnostics.HealthChecks указывается неявно. Чтобы выполнить проверки работоспособности с помощью Entity Framework Core, добавьте ссылку на пакет в пакет Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore.

В примере приложения приведен код запуска для демонстрации проверки работоспособности для нескольких сценариев. Сценарий проверки базы данных проверяет работоспособность подключения к базе данных с помощью AspNetCore.Diagnostics.HealthChecks. Сценарий пробы DbContext проверяет базу данных с помощью EF CoreDbContext. Чтобы изучить сценарии для баз данных, пример приложения выполняет следующие действия.

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

В другом сценарии проверки работоспособности демонстрируется способ фильтрации проверок работоспособности по порту управления. Пример приложения требует создания Properties/launchSettings.json файла, включающего URL-адрес управления и порт управления. Дополнительные сведения см. в разделе Фильтр по портам.

Базовая проверка работоспособности

Для многих приложений достаточно конфигурации базовой проверки работоспособности, которая сообщает о доступности приложения для обработки запросов (жизнеспособности).

Базовая конфигурация регистрирует службы проверки работоспособности и вызывает ПО промежуточного слоя для получения ответа о работоспособности в конечной точке по URL-адресу. По умолчанию отдельные проверки работоспособности не регистрируются для тестирования какой-либо конкретной зависимости или подсистемы. Приложение считается работоспособным, если оно способно отвечать на запросы по URL-адресу конечной точки работоспособности. Модуль записи ответа по умолчанию записывает состояние (HealthStatus) в виде обычного текста ответа обратно клиенту; оно указывает на состояние HealthStatus.Healthy, HealthStatus.Degraded или HealthStatus.Unhealthy.

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks в Startup.Configure.

В примере приложения создается /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");
        });
    }
}

Чтобы запустить сценарий базовой конфигурации с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario basic

Пример для Docker

Docker предлагает встроенную директиву HEALTHCHECK, которую можно вызвать для проверки состояния приложения, использующего базовую конфигурацию проверки работоспособности:

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

Создание проверки работоспособности

Проверки работоспособности создаются путем реализации интерфейса IHealthCheck. Метод CheckHealthAsync возвращает HealthCheckResult, что означает состояние работоспособности Healthy, Degraded или Unhealthy. Результат записывается в ответ в виде обычного текста с кодом состояния, который можно настроить (конфигурация описана в разделе Варианты проверки работоспособности). HealthCheckResult также может возвращать необязательные пары "ключ-значение".

Следующий класс ExampleHealthCheck демонстрирует структуру процесса проверки работоспособности. Логика проверок работоспособности помещается в метод CheckHealthAsync. В следующем примере для true задается фиктивная переменная healthCheckResultHealthy. Если healthCheckResultHealthy задано значение false, возвращается состояние HealthCheckResult.Unhealthy.

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

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

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

Зарегистрируйте службы проверки работоспособности

Тип ExampleHealthCheck будет добавлен к службам проверки работоспособности с помощью AddCheck в Startup.ConfigureServices:

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

Перегрузка AddCheck, показанная в следующем примере, устанавливает состояние сбоя (HealthStatus) для отчета в ситуации, когда проверка работоспособности сообщает о сбое. Если присвоено состояние сбоя null (по умолчанию), сообщается HealthStatus.Unhealthy. Эта перегрузка — полезный сценарий для авторов библиотек, где состояние сбоя от библиотеки особо учитывается приложением при сбое проверки работоспособности, если реализация проверки работоспособности учитывает этот параметр.

Теги можно использовать для фильтрации проверок работоспособности (описаны далее в разделе Фильтрация проверок работоспособности).

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

AddCheck также может выполнять лямбда-функции. В следующем примере имя проверки работоспособности указано как Example; проверка всегда возвращает работоспособное состояние:

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

Вызовите AddTypeActivatedCheck, чтобы передать аргументы реализации проверки работоспособности. В следующем примере TestHealthCheckWithArgs принимает целое число и строку для использования при вызове CheckHealthAsync:

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

    public int I { get; set; }

    public string S { get; set; }

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

TestHealthCheckWithArgs регистрируется путем вызова AddTypeActivatedCheck с целым числом и строкой, передаваемой в реализацию:

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

Использование маршрутизации при проверках работоспособности

В Startup.Configure вызовите MapHealthChecks для построителя конечной точки с URL-адресом конечной точки или относительным путем:

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

RequireHost

Вызовите RequireHost, чтобы указать один или несколько разрешенных узлов для конечной точки проверки работоспособности. Узлы должны быть указаны в Юникоде, а не Punycode, и могут включать порт. Если коллекция не указана, допускается любой узел.

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

Дополнительные сведения см. в разделе Фильтр по портам.

RequireAuthorization

Вызовите RequireAuthorization для запуска ПО промежуточного слоя для авторизации в конечной точке запроса проверки работоспособности. Перегрузка RequireAuthorization принимает одну или несколько политик авторизации. Если политика не указана, используется политика авторизации по умолчанию.

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

Включение запросов о происхождении (CORS)

Хотя выполнение проверок работоспособности вручную из браузера не является распространенным сценарием использования, ПО промежуточного слоя CORS можно включить, вызвав RequireCors в конечных точках проверки работоспособности. Перегрузка RequireCors принимает делегат построителя политики CORS (CorsPolicyBuilder) или имя политики. Если политика не указана, используется политика CORS по умолчанию. Дополнительные сведения см. в статье Включение запросов CORS в ASP.NET Core.

Варианты проверки работоспособности

HealthCheckOptions предоставляет возможность настройки поведения для проверки работоспособности:

Фильтрация проверок работоспособности

По умолчанию ПО промежуточного слоя для проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить подмножество проверок работоспособности, укажите функцию, которая возвращает логическое значение через параметр Predicate. В следующем примере проверка работоспособности Bar отфильтровывается по тегу (bar_tag) в условном операторе функции, где true возвращается только в том случае, если свойство проверки работоспособности Tags соответствует foo_tag или baz_tag:

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

В Startup.ConfigurePredicate определяет, что проверка работоспособности Bar не выполняется. Выполняется только проверка работоспособности Foo и Baz:

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

Настройка кода состояния HTTP

Используйте ResultStatusCodes для настройки сопоставления состояний работоспособности и кодов состояния HTTP. Следующие назначения StatusCodes являются значениями по умолчанию, используемыми ПО промежуточного слоя. Измените значения кодов состояния в соответствии с требованиями.

В Startup.Configure:

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

Подавление заголовков кэша

AllowCachingResponses определяет, добавляет ли ПО промежуточного слоя HTTP-заголовки в ответ проверки, чтобы предотвратить кэширование ответов. Если значение равно false (по умолчанию), ПО промежуточного слоя задает или переопределяет заголовки Cache-Control, Expires и Pragma, чтобы предотвратить кэширование ответов. Если значение равно true, ПО промежуточного слоя не изменяет заголовки кэша в ответе.

В Startup.Configure:

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

Настройка выходных данных

В Startup.Configure задайте параметр HealthCheckOptions.ResponseWriter для делегата для записи ответа:

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

Делегат по умолчанию записывает минимальный ответ в виде открытого текста со строковым значением HealthReport.Status. Следующие пользовательские делегаты выводят настраиваемый ответ JSON.

В первом примере из примера приложения показано, как использовать 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);
    }
}

Во втором примере показано, как использовать 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));
}

В примере приложения закомментируйте директиву SYSTEM_TEXT_JSON препроцессора, CustomWriterStartup.cs чтобы включить версию .WriteResponseNewtonsoft.Json

API проверки работоспособности не предоставляет встроенной поддержки сложных форматов возврата JSON, так как формат зависит от выбранной системы мониторинга. При необходимости настройте ответ в предыдущих примерах. Дополнительные сведения о сериализации JSON с System.Text.Json см. в статье о сериализации и десериализации JSON в .NET.

Проверка базы данных

Проверка работоспособности может задать запрос для выполнения в качестве логического теста для указания того, отвечает ли база данных как обычно.

Пример приложения использует AspNetCore.Diagnostics.HealthChecks, библиотеку проверки работоспособности для приложений ASP.NET Core, чтобы проверить работоспособность базы данных SQL Server. AspNetCore.Diagnostics.HealthChecks выполняет запрос SELECT 1 к базе данных, чтобы подтвердить, что подключение к базе данных находится в работоспособном состоянии.

Предупреждение

При проверке подключения к базе данных с помощью запроса выберите запрос, возвращающий результат быстро. Метод запроса связан с риском перегрузки базы данных и снижения ее производительности. В большинстве случаев тестовый запрос не является обязательным. Достаточно успешного подключения к базе данных. Если вам понадобится выполнить запрос, выберите простой запрос SELECT, например SELECT 1.

Включите ссылку на пакет для AspNetCore.HealthChecks.SqlServer.

Укажите допустимую строку подключения к базе данных в файле примера приложения appsettings.json. Приложение использует базу данных SQL Server с именем 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": "*"
}

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Пример приложения вызывает AddSqlServer метод с строка подключения базы данных (DbHealthStartup.cs):

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure:

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

Чтобы запустить сценарий проверки базы данных с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario db

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Проверка DbContext в Entity Framework Core

Проверка DbContext подтверждает, что приложение может взаимодействовать с базой данных, настроенной EF CoreDbContextдля объекта. Проверка DbContext поддерживается в приложениях, которые:

AddDbContextCheck<TContext> регистрирует проверку работоспособности для DbContext. DbContext передается методу в качестве TContext. Доступна перегрузка, позволяющая настроить состояние ошибки, теги и запрос тестирования.

По умолчанию:

  • Метод DbContextHealthCheck вызоваEF CoreCanConnectAsync. Вы можете указать, какая операция выполняется в том случае, когда проверка работоспособности производится с помощью перегрузок метода AddDbContextCheck.
  • Имя проверки работоспособности — это имя типа TContext.

В примере приложения AppDbContext предоставляется для AddDbContextCheck и регистрируется в качестве службы в Startup.ConfigureServices (DbContextHealthStartup.cs):

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

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure:

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

Прежде чем запускать сценарий проверки DbContext с помощью примера приложения, убедитесь, что база данных, указанная в строке подключения, не существует в экземпляре SQL Server. Если база данных существует, удалите ее.

Выполните следующую команду в папке проекта в командной строке:

dotnet run --scenario dbcontext

После запуска приложения проверьте состояние работоспособности, выполнив запрос к конечной точке /health в браузере. Базы данных и AppDbContext не существуют, поэтому приложение дает следующий ответ:

Unhealthy

Заставьте пример приложения создать базу данных. Сделайте запрос к /createdatabase. Приложение выдает ответ:

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

Сделайте запрос к конечной точке /health. База данных и контекст существуют, поэтому приложение отвечает:

Healthy

Заставьте пример приложения удалить базу данных. Сделайте запрос к /deletedatabase. Приложение выдает ответ:

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

Сделайте запрос к конечной точке /health. Приложение предоставляет ответ о неработоспособности:

Unhealthy

Разделение проверок готовности и активности

В некоторых сценариях размещения используется пара проверок работоспособности, отличающая два состояния приложения:

  • Готовность указывает, что приложение работает нормально, но не готово к приему запросов.
  • Активность указывает на сбой приложения, и его необходимо перезапустить.

Рассмотрим следующий пример: приложение должно скачать большой файл конфигурации, прежде чем он готов к обработке запросов. Нам не требуется перезапуск приложения в случае сбоя начальной загрузки, так как приложение может повторить попытку скачивания файла несколько раз. Для описания активности процесса используется проба активности, дополнительные проверки не выполняются. Кроме того, мы хотим предотвратить отправку запросов в приложение до успешной загрузки файла конфигурации. Мы используем пробу активности, чтобы указать состояние "не готово" до тех пор, пока загрузка не будет завершена и приложение не сможет принимать запросы.

Пример приложения содержит проверку работоспособности, которая сообщает о завершении длительной задачи запуска размещенной службы. Предоставляет StartupHostedServiceHealthCheck свойство, StartupTaskCompletedкоторое размещенная служба может задать, true когда ее долго выполняющаяся задача (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."));
    }
}

Длительная фоновая задача запущена размещенной службой (Services/StartupHostedService). По завершении задачи StartupHostedServiceHealthCheck.StartupTaskCompleted получает значение 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()
    {
    }
}

Проверка работоспособности регистрируется через AddCheck в Startup.ConfigureServices вместе с размещенной службой. Так как размещенная служба должна задать свойство проверки работоспособности, проверка работоспособности также регистрируется в контейнере службы (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>();

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure. В примере приложения конечные точки проверки работоспособности создаются в следующих расположениях:

  • В /health/ready для проверки готовности. Проверка готовности фильтрует проверки работоспособности по тегу ready.
  • В /health/live для проверки жизнеспособности. Проверка жизнеспособности отфильтровывает StartupHostedServiceHealthCheck, возвращая false в HealthCheckOptions.Predicate (дополнительные сведения см. в разделе Фильтрация проверок работоспособности).

В следующем примере кода происходит следующее:

  • Проверка готовности использует все зарегистрированные проверки с тегом ready.
  • Predicate исключает все проверки и возвращает состояние "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
    });
}

Чтобы запустить сценарий конфигурации проверок готовности и жизнеспособности с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario liveness

В браузере посетите /health/ready несколько раз, пока не пройдет 15 секунд. Проверка работоспособности будет передавать Unhealthy первые 15 секунд. По истечении 15 секунд конечная точка передает состояние Healthy, отражающее завершение длительной задачи размещенной службой.

В этом примере также создается издатель проверки работоспособности (реализация IHealthCheckPublisher), который выполнит первую проверку готовности с задержкой в две секунды. Дополнительные сведения см. в разделе об издателе проверки работоспособности.

Пример для Kubernetes

Использование отдельных проверок готовности и жизнеспособности полезно в таких средах, как Kubernetes. В Kubernetes приложениям может потребоваться долго выполнять задачи во время запуска, прежде чем начать принимать запросы; например, проверить доступность основной базы данных. Использование отдельных проверок позволяет оркестратору различать, когда приложение работает, но еще не готово, а когда приложение не удалось запустить. Дополнительные сведения о проверках готовности и жизнеспособности в Kubernetes см. в разделе Настройка проверок готовности и жизнеспособности в документации по Kubernetes.

В следующем примере показана конфигурация проверки готовности для 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

Проба на основе метрики с настраиваемым модулем записи ответов

Этот пример демонстрирует проверку работоспособности памяти с настраиваемым модулем записи ответов.

Если приложение использует больше заданного порогового значения памяти (1 ГБ в примере приложения), MemoryHealthCheck сообщает о состоянии пониженной функциональности. Сведения HealthCheckResult о сборщике мусора (GC) для приложения (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));
    }
}

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Вместо того чтобы включать проверку работоспособности, передав ее в AddCheck, MemoryHealthCheck регистрируется в качестве службы. Все зарегистрированные службы IHealthCheck доступны в службах проверки работоспособности и ПО промежуточного слоя. Мы рекомендуем регистрировать службы проверки работоспособности в качестве одноэлементных служб.

В CustomWriterStartup.cs примере приложения:

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

Конечная точка проверки работоспособности создается путем вызова MapHealthChecks в Startup.Configure. Делегат WriteResponse передается в свойство ResponseWriter для вывода настраиваемого ответа JSON при выполнении проверки работоспособности:

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

Делегат WriteResponse форматирует CompositeHealthCheckResult в объект JSON и выдает выходные данные JSON в качестве ответа проверки работоспособности. Дополнительные сведения см. в разделе Настройка выходных данных.

Чтобы запустить проверку метрики с настраиваемым модулем записи ответа с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario writer

Примечание.

AspNetCore.Diagnostics.HealthChecks включает сценарии для проверки работоспособности на основе метрик, включая проверки жизнеспособности для дискового хранилища и максимальных значений.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Фильтр по портам

Вызовите RequireHost в MapHealthChecks с шаблоном URL-адреса, в котором указан порт для ограничения запросов проверки работоспособности указанным портом. Обычно этот подход используется в контейнерной среде с целью предоставления порта для мониторинга служб.

Пример приложения настраивает порт с помощью поставщика конфигурации переменных среды. Порт задается в launchSettings.json файле и передается поставщику конфигурации через переменную среды. Необходимо также настроить на сервере прослушивание запросов через порт управления.

Чтобы использовать пример приложения для демонстрации конфигурации порта управления, создайте launchSettings.json файл в папке Properties .

Properties/launchSettings.json Следующий файл в примере приложения не включен в файлы проекта примера приложения и должен быть создан вручную:

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

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Startup.ConfigureServices. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks в Startup.Configure.

В примере приложения вызов RequireHost в конечной точке в Startup.Configure указывает порт управления из конфигурации:

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

Конечные точки создаются в примере приложения в Startup.Configure. В следующем примере кода происходит следующее:

  • Проверка готовности использует все зарегистрированные проверки с тегом ready.
  • Predicate исключает все проверки и возвращает состояние "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
    });
}

Примечание.

Вы можете избежать создания launchSettings.json файла в примере приложения, задав порт управления явным образом в коде. В Program.cs месте HostBuilder создания добавьте вызов ListenAnyIP и укажите конечную точку порта управления приложения. В Configure этом ManagementPortStartup.csслучае укажите порт управления с помощью 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");
});

Чтобы запустить сценарий с портом управления с помощью примера приложения, выполните следующую команду из папки проекта в командной строке:

dotnet run --scenario port

Распространение библиотеки проверки работоспособности

Чтобы распространять проверки работоспособности в качестве библиотеки, выполните следующие действия.

  1. Напишите проверку работоспособности, которая реализует интерфейс IHealthCheck как автономный класс. Класс может полагаться на внедрение зависимостей (DI), активацию типов и именованные параметры для доступа к данным конфигурации.

    Логика проверки работоспособности CheckHealthAsync предусматривает следующее:

    • Использование в методе data1 и data2 для выполнения логики проверки работоспособности.
    • Обработку AccessViolationException.

    Когда происходит AccessViolationException, FailureStatus возвращается вместе с HealthCheckResult, что позволяет пользователям настраивать состояние сбоя проверки работоспособности.

    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. Напишите метод расширения с параметрами, который приложение вызывает в своем методе Startup.Configure. В следующем примере предполагается следующая сигнатура метода проверки работоспособности:

    ExampleHealthCheck(string, string, int )
    

    Эта сигнатура указывает, что ExampleHealthCheck требуются дополнительные данные для обработки логики проверки работоспособности. Данные передаются делегату, используемому для создания экземпляра проверки работоспособности, когда проверка работоспособности регистрируется с помощью метода расширения. В следующем примере вызывающая сторона задает:

    • Необязательное имя проверки работоспособности (name). Если null, используется example_health_check.
    • Строковая точка данных для проверки работоспособности (data1).
    • Целочисленная точка данных для проверки работоспособности (data2). Если null, используется 1.
    • состояние сбоя (HealthStatus). Значение по умолчанию — null. Если null, состояние сбоя передается как HealthStatus.Unhealthy.
    • Теги (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));
        }
    }
    

Издатель проверки работоспособности

Когда IHealthCheckPublisher добавляется в контейнер службы, система проверки работоспособности периодически выполняет ваши проверки работоспособности и вызывает PublishAsync с полученным результатом. Это полезно в ситуации принудительной передачи данных мониторинга работоспособности, когда ожидается, что каждый процесс периодически вызывает систему мониторинга для определения работоспособности.

Интерфейс IHealthCheckPublisher содержит один метод:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions позволяет задать следующие параметры:

  • Delay: начальная задержка, примененная после запуска приложения перед выполнением IHealthCheckPublisher экземпляров. Задержка применяется при запуске один раз и не распространяется на все последующие итерации. Значение по умолчанию — пять секунд.
  • Period: период IHealthCheckPublisher выполнения. Значение по умолчанию — 30 секунд.
  • Predicate: если Predicate задано null (по умолчанию), служба издателя проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить ряд проверок работоспособности, укажите функцию, которая отфильтровывает нужный набор. Предикат вычисляется в каждом периоде.
  • Timeout: время ожидания для выполнения проверок работоспособности для всех IHealthCheckPublisher экземпляров. Используйте InfiniteTimeSpan, чтобы выполнить проверки без задержки. Значение по умолчанию — 30 секунд.

В примере приложения ReadinessPublisher является реализацией IHealthCheckPublisher. Состояние проверки работоспособности записывается для каждой проверки на таком уровне журнала:

  • на уровне сведений (LogInformation), если состояние проверки работоспособности — Healthy;
  • на уровне ошибки (LogError), если состояние соответствует Degraded или Unhealthy.
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;
    }
}

В примере приложения LivenessProbeStartup проверка готовности StartupHostedService использует задержку запуска в две секунды и выполняет проверку каждые 30 секунд. Чтобы активировать реализацию IHealthCheckPublisher, этот пример регистрирует ReadinessPublisher как отдельную службу в контейнере внедрения зависимостей.

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

Примечание.

AspNetCore.Diagnostics.HealthChecks включает издатели для нескольких систем, в том числе Application Insights.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Ограничение проверок работоспособности с помощью MapWhen

Используйте MapWhen для условного ветвления конвейера запросов для конечных точек проверки работоспособности.

В следующем примере MapWhen выполняет ветвление конвейера запросов для активации ПО промежуточного слоя для проверки работоспособности, если для конечной точки api/HealthCheck поступает запрос GET:

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

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

Дополнительные сведения см. в статье ПО промежуточного слоя ASP.NET Core.

ASP.NET Core предоставляет ПО промежуточного слоя и библиотеки для создания отчетов о работоспособности компонентов инфраструктуры приложения.

Проверки работоспособности предоставляются приложением как конечные точки HTTP. Конечные точки проверки работоспособности можно настроить для различных сценариев мониторинга в реальном времени:

  • Проверки работоспособности можно использовать с оркестраторами контейнеров и подсистемами балансировки нагрузки, чтобы проверять состояние приложения. Например, оркестратор контейнеров может реагировать на неуспешную проверку работоспособности, остановив последовательное развертывание или перезапустив контейнер. Балансировщик нагрузки может реагировать на неработоспособное приложение путем перенаправления трафика от неисправного экземпляра к работающему экземпляру.
  • Использование памяти, диска и других ресурсов физического сервера можно отслеживать с точки зрения работоспособности.
  • Проверки работоспособности позволяют проверять зависимости приложения, такие как базы данных и конечные точки внешних служб, чтобы убедиться в доступности и нормальной работе.

Проверки работоспособности обычно используются в оркестраторе контейнеров или внешней службе мониторинга для проверки состояния приложения. Перед добавлением проверки работоспособности приложения выберите используемую систему мониторинга. Система мониторинга определяет, какие виды проверки работоспособности создавать и как настроить их конечные точки.

Базовая проверка работоспособности

Для многих приложений достаточно конфигурации базовой проверки работоспособности, которая сообщает о доступности приложения для обработки запросов (жизнеспособности).

Базовая конфигурация регистрирует службы проверки работоспособности и вызывает ПО промежуточного слоя для получения ответа о работоспособности в конечной точке по URL-адресу. По умолчанию отдельные проверки работоспособности не регистрируются для тестирования какой-либо конкретной зависимости или подсистемы. Приложение считается работоспособным, если оно способно отвечать на запросы по URL-адресу конечной точки работоспособности. Модуль записи ответа по умолчанию записывает HealthStatus в качестве ответа клиенту в виде простого текста. Значение HealthStatus равно HealthStatus.Healthy, HealthStatus.Degraded или HealthStatus.Unhealthy.

Зарегистрируйте службы проверки работоспособности при помощи AddHealthChecks в Program.cs. Создайте конечную точку проверки работоспособности, вызвав MapHealthChecks.

В примере ниже создается конечная точка проверки работоспособности в /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker предлагает встроенную директиву HEALTHCHECK, которую можно вызвать для проверки состояния приложения, использующего базовую конфигурацию проверки работоспособности:

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

В предыдущем примере используется curl, чтобы выполнить HTTP-запрос к конечной точке проверки работоспособности по адресу /healthz. curl не входит в образы контейнеров .NET Linux, но его можно добавить, установив необходимый пакет в Dockerfile. Контейнеры, использующие образы на основе Alpine Linux, могут использовать включенный wget вместо curl.

Создание проверки работоспособности

Проверки работоспособности создаются путем реализации интерфейса IHealthCheck. Метод CheckHealthAsync возвращает HealthCheckResult, что означает состояние работоспособности Healthy, Degraded или Unhealthy. Результат записывается как ответ в виде простого текста с настраиваемым кодом состояния. Конфигурация описана в разделе Параметры проверки работоспособности. HealthCheckResult также может возвращать необязательные пары "ключ-значение".

Следующий пример демонстрирует структуру процесса проверки работоспособности:

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

Логика проверки работоспособности помещается в метод CheckHealthAsync. В предыдущем примере для фиктивной переменной isHealthy задается значение true. Если isHealthy задано значение false, возвращается состояние HealthCheckRegistration.FailureStatus.

Если CheckHealthAsync вызывает исключение во время проверки, возвращается новый объект HealthReportEntry, у которого HealthReportEntry.Status равняется FailureStatus. Это состояние определяется AddCheck (см. раздел Зарегистрируйте службы проверки работоспособности) и включает внутреннее исключение, вызвавшее сбой проверки. Для сообщения исключения задается свойство Description.

Зарегистрируйте службы проверки работоспособности

Чтобы зарегистрировать службу проверки работоспособности, вызовите AddCheck в Program.cs:

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

Перегрузка AddCheck, показанная в следующем примере, устанавливает состояние сбоя (HealthStatus) для отчета в ситуации, когда проверка работоспособности сообщает о сбое. Если присвоено состояние сбоя null (по умолчанию), сообщается HealthStatus.Unhealthy. Эта перегрузка — полезный сценарий для авторов библиотек, где состояние сбоя от библиотеки особо учитывается приложением при сбое проверки работоспособности, если реализация проверки работоспособности учитывает этот параметр.

Теги можно использовать для фильтрации проверок работоспособности. Теги описаны в разделе Фильтрация проверок работоспособности.

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

AddCheck также может выполнять лямбда-функции. В следующем примере проверка работоспособности всегда возвращает работоспособное состояние:

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

Вызовите AddTypeActivatedCheck, чтобы передать аргументы реализации проверки работоспособности. В следующем примере проверка работоспособности, активируемая с помощью типа, принимает целое число и строку в своем конструкторе:

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

Чтобы зарегистрировать предыдущую проверку работоспособности, вызовите метод AddTypeActivatedCheck, передав целое число и строку в качестве аргументов:

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

Использование маршрутизации при проверках работоспособности

В Program.cs вызовите MapHealthChecks для построителя конечной точки с URL-адресом конечной точки или относительным путем:

app.MapHealthChecks("/healthz");

RequireHost

Вызовите RequireHost, чтобы указать один или несколько разрешенных узлов для конечной точки проверки работоспособности. Узлы должны быть указаны в Юникоде, а не Punycode, и могут включать порт. Если коллекция не указана, допускается любой узел:

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

Чтобы ограничить конечную точку проверки работоспособности, чтобы она отвечала только на конкретный порт, укажите порт в вызове RequireHost. Обычно этот подход используется в контейнерной среде с целью предоставления порта для мониторинга служб:

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

Предупреждение

API, основанный на заголовке узла, например HttpRequest.Host и RequireHost, подвержены потенциальному спуфинду клиентов.

Чтобы предотвратить спуфинирование узлов и портов, используйте один из следующих подходов:

Чтобы запретить несанкционированным клиентам спуфинировать порт, вызовите следующую команду RequireAuthorization:

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

Дополнительные сведения см. в статье Сопоставление узлов в маршрутах с помощью RequireHost.

RequireAuthorization

Вызовите RequireAuthorization для запуска ПО промежуточного слоя для авторизации в конечной точке запроса проверки работоспособности. Перегрузка RequireAuthorization принимает одну или несколько политик авторизации. Если политика не указана, используется политика авторизации по умолчанию:

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

Включение запросов о происхождении (CORS)

Хотя выполнение проверок работоспособности вручную из браузера — не распространенный сценарий, можно включить ПО промежуточного слоя CORS, вызывая RequireCors в конечных точках проверки работоспособности. Перегрузка RequireCors принимает делегат построителя политики CORS (CorsPolicyBuilder) или имя политики. Дополнительные сведения см. в статье Включение запросов CORS в ASP.NET Core.

Варианты проверки работоспособности

HealthCheckOptions предоставляет возможность настройки поведения для проверки работоспособности:

Фильтрация проверок работоспособности

По умолчанию ПО промежуточного слоя для проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить подмножество проверок работоспособности, укажите функцию, которая возвращает логическое значение через параметр Predicate.

В следующем примере выполняется фильтрация проверок работоспособности, чтобы запускались только те, у которых есть тег sample:

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

Настройка кода состояния HTTP

Используйте ResultStatusCodes для настройки сопоставления состояний работоспособности и кодов состояния HTTP. Следующие назначения StatusCodes являются значениями по умолчанию, используемыми ПО промежуточного слоя. Измените значения кодов состояния в соответствии с требованиями:

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

Подавление заголовков кэша

AllowCachingResponses определяет, добавляет ли ПО промежуточного слоя HTTP-заголовки в ответ проверки, чтобы предотвратить кэширование ответов. Если значение равно false (по умолчанию), ПО промежуточного слоя задает или переопределяет заголовки Cache-Control, Expires и Pragma, чтобы предотвратить кэширование ответов. Если значение равно true, ПО промежуточного слоя не изменяет заголовки кэша в ответе:

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

Настройка выходных данных

Чтобы настроить вывод отчета о проверках работоспособности, присвойте свойству HealthCheckOptions.ResponseWriter делегат, записывающий ответ:

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

Делегат по умолчанию записывает минимальный ответ в виде открытого текста со строковым значением HealthReport.Status. Следующий пользовательский делегат выводит настраиваемый ответ JSON с помощью 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()));
}

API проверки работоспособности не предоставляет встроенной поддержки сложных форматов возврата JSON, так как формат зависит от выбранной системы мониторинга. При необходимости настройте ответ в предыдущих примерах. Дополнительные сведения о сериализации JSON с System.Text.Json см. в статье о сериализации и десериализации JSON в .NET.

Проверка базы данных

Проверка работоспособности может задать запрос для выполнения в качестве логического теста для указания того, отвечает ли база данных как обычно.

AspNetCore.Diagnostics.HealthChecks, библиотека проверки работоспособности для приложений ASP.NET Core включает проверку работоспособности, которая выполняется для базы данных SQL Server. AspNetCore.Diagnostics.HealthChecks выполняет запрос SELECT 1 к базе данных, чтобы подтвердить, что подключение к базе данных находится в работоспособном состоянии.

Предупреждение

При проверке подключения к базе данных с помощью запроса выберите запрос, возвращающий результат быстро. Метод запроса связан с риском перегрузки базы данных и снижения ее производительности. В большинстве случаев тестовый запрос не является обязательным. Достаточно успешного подключения к базе данных. Если вам понадобится выполнить запрос, выберите простой запрос SELECT, например SELECT 1.

Чтобы использовать эту проверку работоспособности SQL Server, включите ссылку на пакет NuGet AspNetCore.HealthChecks.SqlServer. В следующем примере регистрируется проверка работоспособности SQL Server:

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

Примечание.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Проверка DbContext в Entity Framework Core

Проверка DbContext подтверждает, что приложение может взаимодействовать с базой данных, настроенной EF CoreDbContextдля объекта. Проверка DbContext поддерживается в приложениях, которые:

AddDbContextCheck регистрирует проверку работоспособности для DbContext. DbContext передается методу в качестве TContext. Доступна перегрузка, позволяющая настроить состояние ошибки, теги и запрос тестирования.

По умолчанию:

  • Метод DbContextHealthCheck вызоваEF CoreCanConnectAsync. Вы можете указать, какая операция выполняется в том случае, когда проверка работоспособности производится с помощью перегрузок метода AddDbContextCheck.
  • Имя проверки работоспособности — это имя типа TContext.

В следующем примере показано, как зарегистрировать DbContext и связанный объект DbContextHealthCheck:

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

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

Разделение проверок готовности и активности

В некоторых сценариях размещения используется пара проверок работоспособности, отличающая два состояния приложения:

  • Готовность указывает, что приложение работает нормально, но не готово к приему запросов.
  • Активность указывает на сбой приложения, и его необходимо перезапустить.

Рассмотрим следующий пример: приложение должно скачать большой файл конфигурации, прежде чем он готов к обработке запросов. Нам не требуется перезапуск приложения в случае сбоя начальной загрузки, так как приложение может повторить попытку скачивания файла несколько раз. Для описания активности процесса используется проба активности, дополнительные проверки не выполняются. Кроме того, мы хотим предотвратить отправку запросов в приложение до успешной загрузки файла конфигурации. Мы используем пробу активности, чтобы указать состояние "не готово" до тех пор, пока загрузка не будет завершена и приложение не сможет принимать запросы.

Следующая фоновая задача имитирует процесс запуска, который занимает примерно 15 секунд. После завершения задача устанавливает для свойства StartupHealthCheck.StartupCompleted значение true:

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

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

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

        _healthCheck.StartupCompleted = true;
    }
}

StartupHealthCheck сообщает о завершении длительной задачи запуска и предоставляет свойство StartupCompleted, которое задается фоновой службой:

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

Проверка работоспособности регистрируется через AddCheck в Program.cs вместе с размещенной службой. Поскольку размещенной службе необходимо задать свойство проверки работоспособности, проверка работоспособности также регистрируется в контейнере службы как singleton:

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

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

Чтобы создать две разные конечные точки проверки работоспособности, вызовите MapHealthChecks два раза:

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

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

В предыдущем примере создаются приведенные ниже конечные точки проверки работоспособности:

  • В /healthz/ready для проверки готовности. Проверка готовности фильтрует проверки работоспособности, оставляя те, которые помечены ready.
  • В /healthz/live для проверки жизнеспособности. Проверка активности отфильтровывает все проверки работоспособности, возвращая false в делегат HealthCheckOptions.Predicate. Дополнительные сведения о фильтрации проверок работоспособности см. в разделе Фильтрация проверок работоспособности в этой статье.

Перед завершением задачи запуска конечная точка /healthz/ready сообщает о состоянии Unhealthy. После завершения задачи запуска эта конечная точка сообщает о состоянии Healthy. Конечная точка /healthz/live исключает все проверки и сообщает о состоянии Healthy всех вызовов.

Пример для Kubernetes

Использование отдельных проверок готовности и жизнеспособности полезно в таких средах, как Kubernetes. В Kubernetes приложениям может потребоваться долго выполнять задачи во время запуска, прежде чем начать принимать запросы; например, проверить доступность основной базы данных. Использование отдельных проверок позволяет оркестратору различать, когда приложение работает, но еще не готово, а когда приложение не удалось запустить. Дополнительные сведения о проверках готовности и жизнеспособности в Kubernetes см. в разделе Настройка проверок готовности и жизнеспособности в документации по Kubernetes.

В следующем примере показана конфигурация проверки готовности для 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

Распространение библиотеки проверки работоспособности

Чтобы распространять проверки работоспособности в качестве библиотеки, выполните следующие действия.

  1. Напишите проверку работоспособности, которая реализует интерфейс IHealthCheck как автономный класс. Класс может полагаться на внедрение зависимостей (DI), активацию типов и именованные параметры для доступа к данным конфигурации.

  2. Напишите метод расширения с параметрами, который приложение вызывает в своем методе Program.cs. Рассмотрим следующий пример проверки работоспособности, который принимает arg1 и arg2 в качестве параметров конструктора:

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

    Эта сигнатура указывает, что проверке работоспособности требуются пользовательские данные для обработки логики проверки работоспособности. Данные передаются делегату, используемому для создания экземпляра проверки работоспособности, когда проверка работоспособности регистрируется с помощью метода расширения. В следующем примере вызывающая сторона задает:

    • arg1 — целочисленная точка данных для проверки работоспособности.
    • arg2 — строковый аргумент для проверки работоспособности.
    • name — необязательное имя проверки работоспособности. При null используется значение по умолчанию.
    • failureStatus — необязательные HealthStatus, который передается в случае состояния неполадки. Если null, используется HealthStatus.Unhealthy.
    • tags — необязательная коллекция тегов IEnumerable<string>.
    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));
        }
    }
    

Издатель проверки работоспособности

Когда IHealthCheckPublisher добавляется в контейнер службы, система проверки работоспособности периодически выполняет ваши проверки работоспособности и вызывает PublishAsync с полученным результатом. Этот процесс полезен в ситуации принудительной передачи данных мониторинга работоспособности, когда ожидается, что каждый процесс периодически вызывает систему мониторинга для определения работоспособности.

HealthCheckPublisherOptions позволяет задать следующие параметры:

  • Delay: начальная задержка, примененная после запуска приложения перед выполнением IHealthCheckPublisher экземпляров. Задержка применяется при запуске один раз и не распространяется на все последующие итерации. Значение по умолчанию — пять секунд.
  • Period: период IHealthCheckPublisher выполнения. Значение по умолчанию — 30 секунд.
  • Predicate: если Predicate задано null (по умолчанию), служба издателя проверки работоспособности выполняет все зарегистрированные проверки работоспособности. Чтобы выполнить ряд проверок работоспособности, укажите функцию, которая отфильтровывает нужный набор. Предикат вычисляется в каждом периоде.
  • Timeout: время ожидания для выполнения проверок работоспособности для всех IHealthCheckPublisher экземпляров. Используйте InfiniteTimeSpan, чтобы выполнить проверки без задержки. Значение по умолчанию — 30 секунд.

Следующий пример демонстрирует структуру издателя проверки работоспособности:

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

        return Task.CompletedTask;
    }
}

Класс HealthCheckPublisherOptions предоставляет свойства для настройки поведения издателя проверки работоспособности.

В следующем примере регистрируется издатель проверки работоспособности как singleton и настраиваются 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 включает издатели для нескольких систем, в том числе Application Insights.

AspNetCore.Diagnostics.HealthChecks не поддерживается и не обслуживается корпорацией Майкрософт.

Внедрение зависимостей и проверка работоспособности

Можно использовать внедрение зависимостей для использования экземпляра определенного Type внутри класса проверки работоспособности. Внедрение зависимостей может быть полезно для внедрения параметров или глобальной конфигурации в проверку работоспособности. Использование внедрения зависимостей не является обычным сценарием для настройки проверок работоспособности. Обычно каждая проверка работоспособности вполне зависит от фактического теста и настраивается с помощью IHealthChecksBuilder методов расширения.

В следующем примере показан пример проверки работоспособности, который извлекает объект конфигурации с помощью внедрения зависимостей:

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

Проверка SampleHealthCheckWithDiConfig работоспособности должна быть добавлена в контейнер службы:

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

Существует два способа сделать проверки работоспособности доступными для вызывающих:

  • UseHealthChecks регистрирует ПО промежуточного слоя для обработки запросов проверки работоспособности в конвейере ПО промежуточного слоя.
  • MapHealthChecks регистрирует конечную точку проверки работоспособности. Конечная точка сопоставляется и выполняется вместе с другими конечными точками в приложении.

Преимуществом использования MapHealthChecks является UseHealthChecks возможность использовать по промежуточному слоям, поддерживающим конечные точки, например авторизацию, и более точное управление политикой сопоставления. Основным преимуществом использования UseHealthChecks является MapHealthChecks управление именно тем, где выполняются проверки работоспособности в конвейере ПО промежуточного слоя.

UseHealthChecks:

  • Завершает конвейер, когда запрос соответствует конечной точке проверки работоспособности. Короткое замыкание часто желательно, так как это позволяет избежать ненужных работ, таких как ведение журнала и другое ПО промежуточного слоя.
  • В основном используется для настройки ПО промежуточного слоя проверки работоспособности в конвейере.
  • Может совпадать с любым путем на порту или пустым null PathString. Позволяет выполнять проверку работоспособности при любом запросе, сделанном на указанный порт.
  • исходный код.

MapHealthChecks Позволяет:

  • Сопоставление определенных маршрутов или конечных точек для проверок работоспособности.
  • Настройка URL-адреса или пути, в котором доступна конечная точка проверки работоспособности.
  • Сопоставление нескольких конечных точек проверки работоспособности с различными маршрутами или конфигурациями. Поддержка нескольких конечных точек:
    • Включает отдельные конечные точки для различных типов проверок работоспособности или компонентов.
    • Используется для разных аспектов работоспособности приложения или применения определенных конфигураций к подмножествам проверок работоспособности.
  • исходный код.

Дополнительные ресурсы

Примечание.

Эта статья была частично создана с помощью искусственного интеллекта. Перед публикацией автор проверил и отредактировал содержимое по мере необходимости. См. раздел Наши принципы использования созданного ИИ содержимого в Microsoft Learn.