Files

11 KiB

Лабораторная 2. PostgreSQL, сессии и Redis/Valkey

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

Это skeleton, а не готовый сервер. Здесь есть задание, контракт и публичные проверки. Реализацию приложения, Dockerfile и требуемую инфраструктуру пишет студент. Язык и framework свободные; UI не обязателен.

Карта курса · Процесс fork/PR · OpenAPI · Семантика API · Проверки · Отчёт · Примеры JSON · Памятка преподавателю

Откуда начинаем

Перенесите собственный минимум lab1. Изменения API: password при регистрации, Basic для создания сессии, Bearer вместо X-User-Id для бизнес-запросов.

Архитектура: Клиент → API → PostgreSQL; на 4 появляется Redis ИЛИ Valkey для сессий/кэша.

Что сделать

  1. Опишите таблицы, ограничения, индексы и транзакционные границы до написания запросов. Добавьте версионируемые миграции.
  2. Перенесите пользователей, чаты, членство и сообщения в PostgreSQL. Не используйте SQLite как замену PostgreSQL в принимаемом стенде.
  3. Реализуйте регистрацию с password KDF, вход через Basic, opaque Bearer-сессию, expiry и logout. Действующие сессии тоже должны сохраняться.
  4. Подготовьте единый локальный запуск API и БД (Compose рекомендуется уже здесь), подключите именованные volumes.
  5. Пройдите smoke и тест полного перезапуска. На 4 добавьте Redis/Valkey с конкретной ролью и повторите эксперимент отказа.

Оценка «3»: работающий минимум

  • Минимум lab1 сохранён с объявленным переходом на новую аутентификацию. Все обязательные данные и ещё действующие сессии переживают рестарт API и хранилищ без удаления volumes.
  • PostgreSQL содержит пользователей, чаты, участников и сообщения. Есть первичные/внешние ключи, уникальность username и миграции с нуля. Составная операция создания чата выполняется атомарно.
  • Basic применяется только на POST /auth/sessions, остальные endpoint требуют Bearer. Есть срок жизни сессии и отзыв; X-User-Id не даёт доступ. Пароли уже хешируются password KDF.
  • make test и make test-persistence ACTION_SCRIPT=scripts/restart.sh проходят. Миграции повторно запускаются без дублирования данных. Secrets/volumes не попадают в Git.

Оценка «4»: уровень стажёра/джуна

Весь уровень 3 и все пункты ниже:

  • Redis ИЛИ Valkey реально используется для сессий с TTL либо осмысленного кэша. Опишите источник истины, политику expiry и инвалидации. Если это единственное хранилище сессий, включите persistence, выдерживающее проверяемый рестарт; один TTL не сохраняет данные.
  • Используются параметризованные запросы/безопасный ORM, ограниченный connection pool и таймауты. Проверены гонка регистрации одинакового username и rollback составной операции.
  • Индекс истории обоснован запросом и EXPLAIN (ANALYZE, BUFFERS) на ≥10 000 сообщениях; пагинация не использует полный scan всей истории на каждую страницу.
  • Есть автоматическая проверка expiry при коротком SESSION_TTL_SECONDS, logout, неверного пароля и недоступности Redis/БД. При потере сервиса приложение возвращает ограниченную ошибку/корректно обходит кэш, не принимает запрос от анонимного пользователя как доверенный.

Оценка «5»: исследование и доказанный результат

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

Трек 1. Согласованность кэша. Покажите на конкурентном сценарии stale read или cache stampede, реализуйте защиту и измерьте число SQL-запросов/latency до и после. Докажите read-after-write из контракта и восстановление после рестарта кэша; одной установки Redis недостаточно.

Трек 2. План запроса и восстановление. Исследуйте ≥100 000 сообщений с неравномерными размерами чатов, сравните ≥2 индекса/запроса и стоимость записи. Сделайте backup → восстановление в новое хранилище → сверку количества и выбранных сообщений. Обсудите время восстановления и границы потери данных.

Как начать и проверить

# Работает прямо в skeleton, Python 3.9+; приложение не запускается:
make check

# После реализации запустите свой сервер/стенд по REPORT.md.
# По умолчанию тест использует http://localhost:8080.
make test

.env.example, compose.example.yaml и contracts/infrastructure.json описывают настройки и роли компонентов. compose.example.yaml — список ролей с пустым services, не запускаемый стенд. Реализуйте свой compose.yaml/stack.yaml, закрепите версии образов, заполните локальный .env и опишите bootstrap/миграции. Все зависимости поднимаются из этого репозитория; ссылка «у меня БД уже установлена» не заменяет воспроизводимость.

# Compose-вариант после реализации:
docker compose --env-file .env config --quiet
docker compose --env-file .env up -d --build
# Дождитесь /health/ready; затем make test.
# Для Swarm укажите эквивалентные build/push/deploy-команды в REPORT.md.

Примеры запросов доступны в examples/requests.http, примеры JSON — в contracts/examples.json. Для полной проверки схемы (по желанию локально; CI делает её автоматически):

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-dev.txt
make validate PYTHON=.venv/bin/python

Smoke не выставляет оценку автоматически. Проверку сохранности/отказов запускайте явно по tests/README.md, остальные доказательства приведите в отчёте.

Сценарий защиты

  1. Применить миграции к пустому volume, создать пользователей, войти, отправить сообщение.
  2. Запустить persistence-сценарий: он держит токен только в памяти тестового процесса; action script перезапускает API и все используемые хранилища, сохраняя volumes.
  3. После готовности тот же токен читает те же данные; после logout — 401. Повторить с отдельным коротким TTL для проверки expiry.
  4. Для 4: показать роль Redis/Valkey, план SQL и ошибку зависимости. Для 5: выполнить выбранный эксперимент.

Что должно быть в PR

Исходники, Dockerfile, миграции, compose.yaml либо эквивалентный воспроизводимый запуск, scripts/restart.sh, собственные тесты и отчёт.

Заполните REPORT.md и шаблон PR, укажите целевую оценку/трек. Не меняйте обязательный контракт и публичные tests ради зелёного результата. Сохраняйте возможности предыдущих лабораторных в пределах объявленных переходов.

Вопросы на защите

  • Что подтверждает COMMIT и какие гарантии зависят от настройки durability?
  • Где хранятся сессии и что будет после flush/restart Redis?
  • Чем аутентификация отличается от доступа к конкретному чату?
  • Почему hash пароля и быстрый checksum имеют разные задачи?

Первичные материалы