Healthcheck FastAPI: почему живой процесс ещё не готов к запросам

У сервиса есть /health, который всегда возвращает 200. Мониторинг зелёный, но пользователи не могут открыть заказы: соединение с базой не устанавливается. Тогда в /health добавляют запрос к базе. Теперь краткий сбой PostgreSQL приводит к перезапуску всех экземпляров API. Получилось два разных вопроса, спрятанных за одним адресом.

Первый вопрос: способен ли процесс продолжать работу или он завис? Второй: стоит ли сейчас направлять ему пользовательские запросы? Для них удобно иметь разные проверки.

Два адреса с разным смыслом

Этот маленький пример демонстрирует разделение. Установка — python -m pip install fastapi uvicorn, запуск main.py — python -m uvicorn main:app.

from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Request

@asynccontextmanager
async def lifespan(app: FastAPI):
    app.state.ready = True
    try:
        yield
    finally:
        app.state.ready = False

app = FastAPI(lifespan=lifespan)

@app.get("/live")
async def live():
    return {"status": "alive"}

@app.get("/ready")
async def ready(request: Request):
    if not request.app.state.ready:
        raise HTTPException(503, "Not ready")
    return {"status": "ready"}

Флаг здесь показывает механизм ответа 503, а не полноценную диагностику PostgreSQL. В рабочем приложении критерий ready выбирают по реальным обязательным ресурсам. Проверка базы должна быть короткой, ограниченной по времени и дешёвой.

Какие последствия у отказа

В Kubernetes неуспешная readiness-проверка убирает Pod из готовых адресов сервиса. Неуспешная liveness-проверка после заданного порога приводит к перезапуску контейнера. Поэтому временная недоступность общей базы не всегда должна становиться причиной liveness-отказа всех API.

Для долгой инициализации существует startup-проверка. Она позволяет отдельно описать время старта, не ослабляя рабочие проверки уже запущенного приложения. Конкретные интервалы и пороги выбирайте по времени прогрева своего сервиса.

Что сломать на учебном стенде

Проверьте три сценария: приложение нормально работает; обязательная зависимость недоступна; процесс приложения остановлен. Для второго случая ожидайте отсутствие нового трафика к неготовому экземпляру, если так настроен балансировщик. Для третьего — обнаружение остановки и восстановление процесса системой запуска.

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

Не помещайте в ответ healthcheck пароли, строки подключения и подробный traceback. Мониторингу достаточно статуса и короткого безопасного кода причины. И помните: Docker healthcheck сам по себе не означает автоматический перезапуск — это разобрано в статье про unhealthy и restart always.

Собрать следующий этап проекта

После первого запуска появляются задачи администратора: служба должна стартовать после перезагрузки, логи — помогать искать сбои, обновление — быть воспроизводимым. На курсе DevOps с нуля эти части соединяются в учебный стенд с Linux, Docker, CI/CD и мониторингом.

Посмотреть программу: DevOps-инженер с нуля: полный курс

Проверить детали: Kubernetes: типы probes, FastAPI lifespan.

Продолжить на практике

  • DevOps-инженер с нуля: полный курс ↗

    Практический курс по DevOps для начинающих: от настройки Linux и сетей до сборки контейнеров, автоматизации в GitLab CI/CD, развёртывания в Kubernetes, мониторинга и восстановления данных на собственном компьютере.

  • FastAPI для начинающих: API с базой данных и тестами ↗

    Соберёте свой первый полноценный backend на FastAPI: с базой данных, регистрацией, JWT-авторизацией и автотестами. 34 коротких урока и 140 заданий с проверкой — бесплатно.