iac/apps/message-hub/CONFIGURATION.md

209 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Конфигурация проекта message-hub
# Версия: 0.1.0
Документ описывает все переменные окружения и способы конфигурирования сервиса.
## Способы конфигурирования
Сервис настраивается **через переменные окружения**. Разбор выполняется в `src/config/` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/). Настройки разбиты на несколько классов, каждый со своим префиксом:
- `Settings` (`src/config/__init__.py`) — общий класс приложения, префикс `SETTINGS_`;
- `DBSettings` (`src/config/db.py`) — префикс `DB_`;
- `KafkaSettings` (`src/config/kafka.py`) — префикс `KAFKA_`;
- `RedisSettings` (`src/config/redis.py`) — префикс `CACHE_`;
- `ServiceConfig` и наследники (`src/config/sarex.py`) — префиксы `SAREX_`, `PM_`, `ISSUES_`, `BI_`, `EAV_`, `PDF_CONVERTER_`;
- `S3Settings` (`src/config/s3.py`) — префикс `S3_`;
- `MailerSettings` (`src/config/mailer.py`) — префикс `MAILER_`;
- `LoggerSettings` (`src/config/logger.py`) — префикс `LOG_`.
Особенности разбора:
- у каждого класса задан `env_file='.env'` и `extra='ignore'` — при наличии файла `.env` в рабочей директории он загружается автоматически, лишние переменные игнорируются;
- вложенных секций через разделитель нет — каждая группа настроек читается отдельным классом по своему префиксу;
- поле `VERIFY_SSL` в `S3Settings` и во всех `ServiceConfig` объявлено с `alias='SETTINGS_VERIFY_SSL'` — то есть единая переменная `SETTINGS_VERIFY_SSL` управляет проверкой TLS-сертификатов сразу для S3 и всех HTTP-клиентов внешних сервисов;
- у большинства полей есть значения по умолчанию, поэтому формально сервис стартует и без `.env`, но с дефолтными (локальными) адресами БД, Kafka, Redis и сервисов.
Отдельного конфиг-файла (yaml/toml) у приложения нет.
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (бинарник) | Файл `.env` в рабочей директории (загружается `pydantic-settings`) и/или переменные окружения процесса |
| Локально (контейнеры) | `docker-compose.yaml`: блок `environment` для сервиса `message-hub` (`PYTHONPATH`, `KAFKA_HOST`, `KAFKA_PORT`) |
| Kubernetes (Helm) | `.helm/values.yaml`: блок `universal-chart.services.message-hub.envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов); базовый чарт — `universal-chart` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) и build-args |
Запуск процесса (`docker/entrypoint.sh`): единый ASGI-процесс поднимается через `gunicorn` с воркерами `uvicorn.workers.UvicornWorker` на `0.0.0.0:8000`:
```
gunicorn -w $WORKERS -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 --timeout $WORKER_TIMEOUT --access-logfile - main:app
```
Приложение `main:app` (`src/main.py`) объединяет в одном ASGI-приложении: FastStream-брокер Kafka (потребители сообщений), HTTP-роуты health-проверок и Socket.IO-сервер (`AsyncServer` поверх `AsyncRedisManager`). Отдельных точек входа для воркеров/крон-задач нет — `pyproject.toml` не содержит `[project.scripts]`.
## Переменные приложения
### App (`SETTINGS_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SETTINGS_TOPICS` | dict (JSON) | `{}` | Соответствие логических топиков (`planning`/`assets`/`issues`) реальным именам топиков Kafka. Валидатор запрещает ключи вне набора `assets`/`planning`/`issues` |
| `SETTINGS_DEBUG` | bool | `False` | Режим отладки |
| `SETTINGS_VERIFY_SSL` | bool | `True` | Проверка TLS-сертификатов для S3 и всех HTTP-клиентов внешних сервисов (общий флаг через alias) |
| `SETTINGS_WORKER_TIMEOUT` | int | `30` | Таймаут воркера (поле `WORKER_TIMEOUT` класса `Settings`) |
| `SETTINGS_RETRY_DELAY` | int | `3` | Стартовая задержка (сек) между повторами обработки сообщения Kafka; удваивается на каждой попытке |
| `SETTINGS_MAX_RETRIES` | int | `3` | Число попыток обработки сообщения Kafka перед `ack` |
| `SETTINGS_REQUEST_RETRIES` | int | `2` | Число повторов HTTP-запросов к внешним сервисам |
| `SETTINGS_REQUEST_DELAY` | int | `2` | Задержка (сек) между повторами HTTP-запросов |
| `SETTINGS_MESSAGE_SKIP_AGE` | int | `300` | Возраст сообщения (сек), старше которого оно пропускается |
| `SETTINGS_CACHE_EXPIRATION` | int | `120` | TTL (сек) ключей присутствия пользователей в Redis (WebSocket) |
| `SETTINGS_SENDER` | string | `noreply@sarex.io` | Адрес отправителя по умолчанию |
### Логирование (`LOG_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `LOG_LEVEL` | string | `INFO` | Уровень логирования (стандартные уровни `logging`) |
| `LOG_FORMAT` | string | `[%(asctime)s] [%(levelname)s] [%(filename)s]: %(message)s` | Формат строк лога |
### Database (`DB_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DB_HOST` | string | `''` | Хост PostgreSQL |
| `DB_PORT` | int | `5432` | Порт PostgreSQL |
| `DB_DATABASE` | string | `''` | Имя базы данных |
| `DB_USERNAME` | string | `''` | Пользователь БД |
| `DB_PASSWORD` | string | `''` | Пароль пользователя БД |
| `DB_DIALECT` | string | `postgresql+psycopg` | Диалект/драйвер SQLAlchemy. Итоговый DSN собирается в `db.url` |
### Kafka (`KAFKA_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `KAFKA_HOST` | string | `localhost` | Хост брокера |
| `KAFKA_PORT` | int | `9092` | Порт брокера |
| `KAFKA_USERNAME` | string \| null | `None` | Логин SASL |
| `KAFKA_PASSWORD` | string \| null | `None` | Пароль SASL |
| `KAFKA_SECURITY_PROTOCOL` | string | `PLAINTEXT` | Протокол безопасности: `PLAINTEXT`/`SSL`/`SASL_PLAINTEXT`/`SASL_SSL`. При `SSL`/`SASL_SSL` используется SSL-контекст |
| `KAFKA_SASL_MECHANISM` | string \| null | `None` | Механизм SASL. Обрабатываются `PLAINTEXT` и `SCRAM-SHA-512` |
| `KAFKA_SSL_CAFILE` | string \| null | `None` | Путь к CA-сертификату для SSL-контекста |
### Redis / кеш (`CACHE_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CACHE_HOST` | string | `localhost` | Хост Redis |
| `CACHE_PORT` | int | `6378` | Порт Redis |
| `CACHE_PASSWORD` | string \| null | `None` | Пароль Redis |
| `CACHE_SSL` | bool | `False` | Подключение по TLS (`rediss://`) |
| `CACHE_SSL_CA_CERTS` | string \| null | `None` | Путь к CA-сертификату Redis |
> Redis используется как менеджер состояния Socket.IO (`AsyncRedisManager`) и как хранилище присутствия пользователей в проектах.
### S3 (`S3_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `S3_HOST` | string | `https://storage.yandexcloud.net` | Endpoint S3 (`endpoint_url`) |
| `S3_LOGIN` | string | `''` | Access key |
| `S3_PASSWORD` | string | `''` | Secret key |
| `S3_BUCKET` | string | `sarex-media-storage` | Бакет по умолчанию |
| `SETTINGS_VERIFY_SSL` | bool | `True` | Проверять TLS-сертификат (общий флаг, см. App) |
### HTTP-клиенты внешних сервисов
Все клиенты наследуют общий класс `ServiceConfig` с полями `HOST`, `TIMEOUT` и общим флагом `VERIFY_SSL` (через alias `SETTINGS_VERIFY_SSL`). Значения по умолчанию: `HOST=http://localhost:8001`, `TIMEOUT=60`.
| Секция / префикс | Назначение |
| --- | --- |
| `SAREX_*` | Sarex backend (получение токенов клиентов и пр.) |
| `PM_*` | PM backend (синхронизация задач, автопланирование) |
| `ISSUES_*` | Сервис issues (типы задач, модели статусов) |
| `BI_*` | BI backend (синхронизация значений аналитики) |
| `EAV_*` | EAV-сервис (ассеты и атрибуты) |
| `PDF_CONVERTER_*` | Конвертер HTML → PDF (export-project) |
Для каждого — две переменные, напр. для PM:
| Переменная | Тип | Назначение |
| --- | --- | --- |
| `PM_HOST` | string | Базовый URL сервиса |
| `PM_TIMEOUT` | int | Таймаут запроса (сек) |
### Mailer (`MAILER_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `MAILER_HOST` | string | `http://localhost:8001` | Базовый URL сервиса рассылок |
| `MAILER_PREFIX` | string | `/api/v1` | Префикс маршрутов сервиса рассылок |
| `MAILER_TIMEOUT` | int | `60` | Таймаут запроса (сек) |
## Переменные инфраструктуры, сборки и запуска
Не читаются классами настроек приложения, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `PYTHONPATH` | `docker-compose.yaml`, Helm `envs` | Каталог исходников (`src`) |
| `WORKERS` | `docker/entrypoint.sh`, Helm `envs` | Число воркеров gunicorn (по умолчанию `2`) |
| `WORKER_TIMEOUT` | `docker/entrypoint.sh`, Helm `envs` | Таймаут воркера gunicorn (`--timeout`) |
| `CI_COMMIT_SHORT_SHA` | `docker/Dockerfile` (build-arg через `BUILD_ARGS`) | Идентификатор сборки |
## Переменные из Helm-чарта (`.helm/values.yaml`)
Сервис деплоится через зависимость `universal-chart`. Обычные значения задаются в блоке `universal-chart.services.message-hub.envs` для окружений `stage`/`preprod`/`production` (различаются адресами БД, Kafka, Redis, сервисов, именами топиков, числом реплик и таймаутами).
Значения из секретов (блок `secretEnvs`, монтируются как env через `secretKeyRef`):
| Переменная | Секрет (`_default` / `production`) | Ключ (`secretKey`) |
| --- | --- | --- |
| `KAFKA_USERNAME` | `message-hub-kafka-secret` / `kafka-secret` | `username` |
| `KAFKA_PASSWORD` | `message-hub-kafka-secret` / `kafka-secret` | `password` |
| `DB_USERNAME` | `pm-postgresql-secret` / `postgres-pm-secret` | `user` |
| `DB_PASSWORD` | `pm-postgresql-secret` / `postgres-pm-secret` | `password` |
| `CACHE_PASSWORD` | `cache-secret-pm` / `cache-secret` | `password` |
| `S3_LOGIN` | `planning-s3-secret` / `s3-secret` | `username` |
| `S3_PASSWORD` | `planning-s3-secret` / `s3-secret` | `password` |
| `S3_BUCKET` | `planning-s3-secret` / `s3-secret` | `bucket` |
| `S3_HOST` | `planning-s3-secret` / `s3-secret` | `host` |
Помимо env, чарт монтирует CA-сертификат из секрета `kafka-secret` (ключ `ssl_cafile`) как файл `/opt/ssl/ca.pem` (том `kafka-ca-volume`, `readOnly`) — на него указывают `KAFKA_SSL_CAFILE` и `CACHE_SSL_CA_CERTS` в конфигурациях окружений.
Health-пробы (`.helm/values.yaml`): liveness `GET /health/live`, readiness `GET /health/ready`, порт `8000`.
## Переменные в CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`:
| Условие | STAND | Namespace | CHART_VERSION |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `planning` | `0.0.1-stage` |
| ветка `master` | `preprod` | `message-hub-preprod` | `0.0.1-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `message-hub-prod` | `0.0.1-prod` |
Ключевые переменные пайплайна: `SERVICE_NAME=message-hub`, `DOCKERFILE_PATH=./docker/Dockerfile`, `BUILD_ARGS`, `CI_TRIGGER_SOURCE=app`, `RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS` (`--set universal-chart...`), флаг `ENABLE_BUILD_IMAGE`. Отдельные job'ы `linter` (`ruff check` / `ruff format --check`) и `typechecker` (`mypy src`).
## Замечания и потенциальные проблемы
- Единая переменная `SETTINGS_VERIFY_SSL` управляет проверкой TLS сразу для S3 и всех шести HTTP-клиентов (alias у поля `VERIFY_SSL`). Отдельно на клиент это не настраивается.
- Поле `WORKER_TIMEOUT` есть и в классе `Settings` (читается как `SETTINGS_WORKER_TIMEOUT`, дефолт `30`), и как самостоятельная переменная `WORKER_TIMEOUT` для gunicorn (`entrypoint.sh`, Helm). Это разные переменные — не перепутайте.
- `SETTINGS_TOPICS` валидируется: допустимы только ключи `assets`, `planning`, `issues`. Прочие ключи вызывают ошибку старта. Если ключ отсутствует, соответствующий потребитель подписывается на пустое имя топика.
- Файл `.env.example` в репозитории сервиса не содержит части переменных (сервисы `PM_/ISSUES_/BI_/EAV_/PDF_CONVERTER_`, `MAILER_`, `LOG_`, ряд `SETTINGS_*`) — при реальном запуске задавайте их явно (полный перечень — в данном документе и в `.env.example` рядом).
- У большинства полей есть дефолты (локальные адреса), поэтому при пустом окружении сервис поднимется, но будет ходить на `localhost` — для рабочих окружений значения задаются через Helm.
## Минимальный набор для локального запуска
Kafka поднимается через `docker-compose.yaml` (сервисы `kafka`, `kafka-ui`); PostgreSQL и Redis — внешние. Минимально стоит задать (с учётом префиксов):
- `SETTINGS_TOPICS` — карта логических топиков в реальные;
- `DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`;
- `KAFKA_HOST`, `KAFKA_PORT` (для docker-compose — `kafka:9092`);
- `CACHE_HOST`, `CACHE_PORT` (+ `CACHE_PASSWORD`/`CACHE_SSL` при необходимости);
- `S3_HOST`, `S3_LOGIN`, `S3_PASSWORD`, `S3_BUCKET`;
- `HOST` для внешних сервисов, которые реально используются (`SAREX_`, `PM_`, `ISSUES_`, `BI_`, `EAV_`, `PDF_CONVERTER_`, `MAILER_`);
- `SETTINGS_VERIFY_SSL` (`0` локально, если сертификаты самоподписанные).
Готовые значения-примеры приведены в `.env.example` рядом с этим документом.