# Конфигурация проекта 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` рядом с этим документом.