Проверки работоспособности
Живой процесс не обязательно готов обслуживать каталог. Приложение может отвечать на простое HTTP-чтение, но потерять подключение к PostgreSQL. С другой стороны, краткая недоступность базы не всегда означает, что процесс нужно немедленно перезапускать. Разделим наблюдение жизни и готовности, чтобы инфраструктура принимала осмысленное решение.
Ветка lesson-29/after в архиве продолжения — отдельное loopback-приложение с двумя health endpoints и Npgsql. Оно использует только подготовленную учебную базу курса, не изменяет таблицы и не подключает настоящий оркестратор. Сервер, SQL, probes и измерения при подготовке не выполнялись. Статусы ниже ожидаются при указанных условиях, но не являются полученными результатами проверки ProfessorWeb.
Liveness отвечает о процессе
Endpoint /health/live не обращается к PostgreSQL. Он показывает, что приложение способно обработать это простое обращение. При работающем host ожидается 200 с текстом Healthy. Такая проверка не гарантирует правильность всех API, наличие нужных данных или отсутствие ошибок в бизнес-логике.
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = _ => false
});
Пустой набор проверок здесь выбран намеренно: зависимость не должна превращать liveness в косвенную проверку всей сети. Если база временно недоступна, повторный restart процесса может только усилить нагрузку и не устранить причину. Решение об остановке не следует делать на основании любого внешнего сбоя.
Однако простая liveness может оставаться зелёной, когда конкретный worker перестал выполнять полезную работу. Для этого требуется дополнительное наблюдение службы, времени последнего успешного действия или очереди. Нельзя раздувать один endpoint до обещания, что система целиком здорова при любых условиях.
Readiness включает выбранную зависимость
В регистрации health check CatalogDatabaseHealth получает tag ready. Endpoint /health/ready выбирает только такие проверки. Внутри выполняется ограниченное чтение схемы courses, чтобы заметить не только доступность сервера PostgreSQL, но и наличие требуемой таблицы и разрешения читать её.
await using var command = source.CreateCommand(
"SELECT id FROM courses LIMIT 1");
command.CommandTimeout = 2;
await command.ExecuteScalarAsync(token);
return HealthCheckResult.Healthy();
Пустая таблица тоже может быть корректным состоянием: отсутствие одной строки не является отказом готовности. Нам нужно, чтобы запрос выполнился, а не чтобы в каталоге обязательно существовал JavaScript. Если продукт требует обязательную конфигурационную запись, такое условие надо добавить отдельно и объяснить, почему пустота означает отказ.
При недоступной базе, отсутствующей схеме или отказе прав check возвращает Unhealthy. По умолчанию соответствующий endpoint получает 503. Подробности исключения не сериализуются наружу: публичное тело остаётся общим. Строка подключения и настоящий текст database error могут раскрывать внутреннюю структуру, поэтому их нельзя отдавать любому посетителю вместе с health.
Таймаут ограничивает проверку, а не создаёт доступность
У health registration выбран общий timeout три секунды, у SQL-команды — две. CancellationToken передаётся в выполнение. Эти числа — учебный budget, а не результат настройки production-нагрузки. Они не означают, что база всегда уложится в нужное время или что истечение немедленно убьёт любую работу на удалённой стороне.
Временной отказ получает отрицательный результат readiness, пока следующий probe не покажет восстановление. Это наблюдение текущего состояния, а не вечный сертификат здоровья. Между успешной проверкой и настоящим пользовательским запросом зависимость может снова отказать. Handler всё равно должен иметь собственные таймауты и обработку ошибок.
Слишком частые probes создают нагрузку, особенно когда каждый открывает соединение и выполняет запрос. Частоту выбирает инфраструктура, а не endpoint. Для маленького SELECT нужен минимальный доступ, но это всё же чтение базы. Нельзя обещать нулевую стоимость только потому, что ответ health короткий.
Пробы не являются административным API
Health endpoints не очищают кеш, не создают схему, не мигрируют таблицы и не запускают recovery. Иначе простое наблюдение может изменить систему, а автоматические повторы — усугубить отказ. В нашем проекте SQL только читает. Он не содержит CREATE, UPDATE или операции очереди.
В примере endpoints доступны на loopback без authentication. Для реального размещения необходимо выбрать отдельную сетевую границу, порт либо согласованную авторизацию инфраструктуры. Попытка вернуть cookie-login redirect probe-клиенту может создать ложное впечатление исправности, если клиент смотрит только на полученный HTML. Проверка должна иметь ясный статус и ожидаемый content type.
Не выводите список всех внутренних зависимостей и версии серверов в публичный ответ без необходимости. Оператору полезен подробный отчёт, но для маршрутизации трафика часто достаточно 200 или 503. Можно иметь отдельный защищённый диагностический канал, не смешивая его с общедоступным endpoint.
Наблюдение связано с действием инфраструктуры
При недоступной базе ожидается: /health/live остаётся 200, /health/ready возвращает 503. Балансировщик мог бы исключить экземпляр из новых запросов, сохраняя процесс для восстановления. В архиве балансировщик и правила restart отсутствуют; статья не утверждает, что именно такая реакция уже настроена на хостинге.
При остановке самого приложения не будет нормального HTTP-ответа ни от одного endpoint. Сетевой timeout и HTTP 503 отличаются: первое может означать отсутствие listener, firewall или проблему маршрута, второе — ответ работающего приложения с отрицательным health. Наблюдатель должен различать эти случаи, а не приводить оба к тексту «сервер умер».
Для будущего выполнения подготовьте правильную учебную схему и проверьте оба адреса. Затем запустите приложение с отдельной строкой к недоступному локальному порту: liveness не должна зависеть от базы, readiness — должна отказать. Не останавливайте рабочую базу сайта ради этого сценария. Исходные таблицы и четыре курса остаются без изменений.
Мы получили два разных сигнала с конкретной целью. Состояние процесса и готовность зависимости теперь не смешаны, но ни один сигнал не заменяет предметные сценарии курса, проверку cookies или реальную нагрузку. Статусы, tags и настройки health checks описаны в официальной документации ASP.NET Core 10.
Готовность может зависеть от начальной загрузки конфигурации или завершения безопасной инициализации. Тогда это отдельный признак, а не попытка выполнить миграцию внутри probe. Если процесс ещё не завершил необходимое чтение, readiness возвращает отказ, но endpoint не делает подготовку повторно на каждом обращении. В нашей ветке такого состояния нет: схема создаётся заранее и check только читает её. Политика балансировщика должна также иметь интервал и порог последовательных отказов, чтобы единичное краткое наблюдение не вызывало постоянного включения и исключения экземпляра. Эти значения остаются задачей будущей инфраструктуры, а не скрытой настройкой приложения в статье.