Глава 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>'
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])
"
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. Сравните с предыдущими запусками, чтобы отличить регрессии от ранее существующих проблем.
Связанные разделы¶
- Мониторинг состояния: инструменты мониторинга
- Работа с базой данных: детали запросов и индексов
- Развёртывание: развёртывание исправлений