Перейти к содержанию

Глава 15: Руководство по устранению неполадок

Аудитория: DevOps, платформенные инженеры

Зацикливание входа

Симптомы: Пользователь попадает на страницу входа, проходит аутентификацию, перенаправляется обратно на страницу входа — цикл повторяется бесконечно.

Паттерн основной причины: Любой сбой базы данных приводит к тому, что _get_or_create_oauth2_user() завершается с тихой ошибкой. /auth/check возвращает {authenticated: false}. Фронтенд перенаправляет на /oauth2/sign_in. Цикл.

Типичные триггеры: - Контейнер Cloud SQL Proxy остановился или был перезапущен без перезапуска API - Сетевая изоляция между ВМ и экземпляром Cloud SQL - Обслуживание или перезапуск экземпляра Cloud SQL

Обнаружение: - Браузер: счётчик редиректов срабатывает после 2 перенаправлений за 30 секунд, отображая интерфейс ошибки/повтора вместо зацикливания - API: /auth/check возвращает HTTP 503 (а не 200), когда база данных недоступна, с полем auth_error в ответе - Логи: ищите ошибки connection refused или timeout в логах catscan-api

Исправление: 1. Проверьте Cloud SQL Proxy: sudo docker ps | grep cloudsql 2. Если не запущен: sudo docker compose -f docker-compose.gcp.yml restart cloudsql-proxy 3. Подождите 10 секунд, затем перезапустите API: sudo docker compose -f docker-compose.gcp.yml restart api 4. Проверьте: curl -sS http://localhost:8000/health

Предотвращение: Трёхуровневое исправление (применено в феврале 2026): 1. Бэкенд передаёт ошибки БД через request.state.auth_error 2. /auth/check возвращает 503, когда БД недоступна 3. Фронтенд имеет счётчик редиректов (максимум 2 за 30 с) + интерфейс ошибки/повтора

Таймаут свежести данных

Симптомы: /uploads/data-freshness возвращает 500, запрос не завершается в срок, или проверка состояния при запуске показывает BLOCKED на этапе проверки данных.

Паттерн основной причины: Запрос свежести данных сканирует большие таблицы (rtb_daily — 84 млн строк, rtb_bidstream — 21 млн строк). Если план запроса деградирует до последовательного сканирования вместо использования индексов, выполнение может занять 160+ секунд.

Обнаружение: 1. Обратитесь к эндпоинту напрямую с ВМ:

curl -sS --max-time 60 -H 'X-Email: cat-scan@rtb.cat' \
  'http://localhost:8000/uploads/data-freshness?days=14&buyer_id=<ID>'
2. Если запрос не завершается в срок или возвращает 500, проверьте план выполнения:
sudo docker exec catscan-api python -c "
import os, psycopg
conn = psycopg.connect(os.environ['POSTGRES_DSN'])
for r in conn.execute('EXPLAIN (ANALYZE, BUFFERS) <query>').fetchall():
    print(list(r.values())[0])
"
3. Ищите Parallel Seq Scan на больших таблицах. Это и есть проблема.

Шаблон исправления: - Перепишите запросы с GROUP BY на generate_series + EXISTS для принудительного использования индексов. См. Работа с базой данных для описания шаблона. - Убедитесь, что используется SET LOCAL statement_timeout (а не SET + RESET). - Проверьте наличие индексов (buyer_account_id, metric_date DESC) на всех целевых таблицах.

Сбой импорта из Gmail

Симптомы: Таблица свежести данных показывает ячейки «missing» для последних дат. В истории импорта отсутствуют свежие записи.

Обнаружение:

curl -sS -H 'X-Email: cat-scan@rtb.cat' \
  http://localhost:8000/gmail/status

Проверьте: last_reason, количество unread, latest_metric_date.

Типичные причины: - Истёк токен Gmail OAuth: повторно авторизуйтесь в /settings/accounts > вкладка Gmail - Cloud SQL Proxy не работает: импорт Gmail записывает в Postgres, поэтому БД должна быть доступна - Большое количество unread (30+): импорт может зависнуть при обработке или в почтовом ящике накопился бэклог

Исправление: 1. Если last_reason показывает ошибку: перезапустите задачу импорта через UI или API 2. Если токен истёк: повторно авторизуйте интеграцию с Gmail 3. Если Cloud SQL не работает: сначала восстановите подключение к базе данных (см. раздел «Зацикливание входа»)

Порядок перезапуска контейнеров

Симптом: Логи API показывают «connection refused» к порту 5432 при запуске.

Причина: Контейнер API запустился раньше, чем Cloud SQL Proxy был готов.

Исправление: Перезапустите с правильным порядком:

sudo docker compose -f docker-compose.gcp.yml up -d cloudsql-proxy
sleep 10
sudo docker compose -f docker-compose.gcp.yml up -d api

Или перезапустите всё (compose учитывает зависимости):

sudo docker compose -f docker-compose.gcp.yml up -d --force-recreate

Синтаксическая ошибка SET statement_timeout

Симптом: Эндпоинт возвращает 500 с ошибкой: syntax error at or near "$1" LINE 1: SET statement_timeout = $1

Причина: psycopg3 преобразует %s в $1 для серверного связывания параметров, но команда PostgreSQL SET не поддерживает подстановку параметров.

Исправление: Используйте f-строку с валидированным целым числом:

# Wrong:
conn.execute("SET statement_timeout = %s", (timeout_ms,))

# Right:
timeout_ms = max(int(statement_timeout_ms), 1)  # validated int
conn.execute(f"SET LOCAL statement_timeout = {timeout_ms}")

Сбой проверки состояния при запуске

Симптом: Рабочий процесс v1-runtime-health-strict.yml завершается с ошибкой.

Диагностика: 1. Проверьте логи рабочего процесса: gh run view <id> --log-failed 2. Определите FAIL или BLOCKED: - FAIL — что-то сломалось, требуется расследование - BLOCKED — отсутствует зависимость (нет данных, нет эндпоинта), может быть ранее существующей проблемой 3. Типичные ранее существующие причины BLOCKED: - «rtb_quality_freshness state is unavailable»: нет данных о качестве для данного байера/периода - «proposal has no billing_id»: проблема настройки данных - «QPS page API rollup missing required paths»: аналитический эндпоинт ещё не заполнен данными 4. Сравните с предыдущими запусками, чтобы отличить регрессии от ранее существующих проблем.

Связанные разделы