Andrey Epifancev 32fa327621 docs: правки по финальному ревью nats-env-config (M-1, M-2, M-5)
- dev/README.md: примеры /healthcheck дополнены subjects по сервисам
- design.md (решение 7) и dev/README.md: уточнено, что запросы в тестах ядра идут на умолчательные subject'ы
- repo-templates: имена files.* помечены как умолчания

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:38:50 +04:00

9.0 KiB
Raw Blame History

Context

Решение владельца 12.10.2026: «топики можно выставлять через секреты и jwt токен тоже, т.к. у нас будут различные наборы топиков и разные jwt для прод и тест окружения». Выбран подход 1 из трёх обсуждённых (12.10.2026):

  1. Выбран: три ключа в группе OPENBAO__NATS__, одинаковые в трёх сервисах.
  2. OPENBAO__APP__* (settings_sources.py) — отвергнут: разносит JWT и subject'ы, на которые он даёт права, по разным группам.
  3. Один префикс NATS_SUBJECT_PREFIX — отвергнут: работает, только если тестовые subject'ы платформы отличаются от боевых префиксом.

Образец — RSHB/armka_file_worker (проверен в контуре): NATSSettings с NATS_URL, NATS_JWT: SecretStr, NATS_SEED: SecretStr, NATS_COMMAND_SUBJECT, NATS_EVENT_SUBJECT; Settings(hide_input_in_errors=True).

Ключ Умолчание arm-core tabular-parser scan-gateway
OPENBAO__NATS__NATS_TABULAR_REQUEST_SUBJECT files.tabular_uploaded публикует подписан (queue tabular-parser) —
OPENBAO__NATS__NATS_IMAGE_REQUEST_SUBJECT files.img_uploaded публикует — подписан (queue scan-gateway)
OPENBAO__NATS__NATS_RESULT_SUBJECT files.tabular_parsed подписан (queue arm-core) публикует публикует

Goals / Non-Goals

Goals: subject'ы и учётные данные NATS задаются секретами окружения; разъехавшиеся настройки видны в /healthcheck; тесты не делят subject'ы со стендом. Non-goals: см. proposal.

Decisions

  1. Ключи одинаковые во всех трёх сервисах, проверяются все три. На окружение — один набор секретов, который платформа кладёт всем сервисам; сервис использует только свои subject'ы, но валидирует все три, чтобы ошибка набора проявилась в любом сервисе одинаково.
  2. Валидация при старте. Имя subject'а — непустое, без пробельных символов, без шаблонов * и >, без пустых токенов (a..b, ведущая или завершающая точка). Три имени попарно различны: совпадение запроса и ответа — сервис получает собственные ответы; совпадение двух запросов — каждый запрос получают оба сервиса. Ошибка — сервис не стартует (ошибка конфигурации, как у DB_SCHEMA).
  3. Константы contract/subjects.py — только умолчания. Код публикации и подписок получает имена из настроек; функция выбора subject'а по pipeline принимает настройки (форма — на усмотрение плана сервиса).
  4. Секреты. NATS_JWT и NATS_SEED — SecretStr; в колбэки nkeys значение передаётся через get_secret_value(); Settings с hide_input_in_errors=True, чтобы ошибка валидации конфигурации не печатала входные значения.
  5. /healthcheck. Новый объект subjects с subject'ами, которые использует сервис: arm-core — tabular_request, image_request, result; tabular-parser — tabular_request, result; scan-gateway — image_request, result. Отдаётся всегда, в том числе при nats = off | down (это конфигурация, не состояние). Решение владельца 12.10.2026: «пусть будет в хэлзчеке».
  6. Лог при старте. Сервис пишет свои subject'ы одной строкой при старте (существующая строка «Подписка NATS активна» сохраняется).
  7. Тесты (OQ-83). Интеграционные тесты tabular-parser и scan-gateway, где обе стороны обмена — в самом тесте, задают уникальные subject'ы через настройки и не пересекаются с контейнерами стенда. e2e ядра (make e2e) остаётся на subject'ах по умолчанию: он гоняет настоящий контейнер tabular-parser стенда, который слушает умолчания, а конфликт там — в общей queue group arm-core на subject'е ответа; требование останавливать ядро стенда сохраняется (R-7). Интеграционные тесты NATS ядра идут на уникальном subject'е ответа; публикации запросов в тестах ядра (test_recognition_exchange.py, test_api_files_upload.py) идут на умолчательные subject'ы запросов и достигают контейнеров стенда.

Risks / Trade-offs

  • Разъехавшиеся настройки ядра и сервиса — тишина на шине: ядро переведёт задания в dlq по NO_ACK. Смягчение: subjects в /healthcheck и лог при старте; в 03-architecture.md — требование задавать набор всем трём сервисам.
  • JWT окружения без прав на заданные subject'ы — ошибка прав NATS при подписке/публикации (в логе сервиса); смягчение — перечень секретов окружения в 03-architecture.md и contour-transfer-guide.md.
  • /healthcheck публичен и теперь раскрывает имена subject'ов. Имена не секретны (без JWT ими не воспользоваться), JWT и seed в ответ не попадают.

Decisions made without discussion

  1. 12.10.2026 — R-1: имена ключей NATS_TABULAR_REQUEST_SUBJECT, NATS_IMAGE_REQUEST_SUBJECT, NATS_RESULT_SUBJECT (по образцу FileWorker — префикс NATS_, суффикс _SUBJECT), а не NATS_COMMAND_SUBJECT / NATS_EVENT_SUBJECT FileWorker: у нас два subject'а запроса. Имена показаны владельцу в дизайне и приняты вместе с подходом. Цена ошибки: низкая — переименование ключа до выката в контур.
  2. 12.10.2026 — R-2: schema_version не меняется: тела сообщений те же, subject'ы — окружение (как R-2 в nats-files-subjects). Цена ошибки: низкая.
  3. 12.10.2026 — R-3: проверяются все три subject'а в каждом сервисе, включая неиспользуемые им (решение 1). Цена ошибки: низкая — лишний отказ старта при кривом наборе, который всё равно сломал бы обмен.
  4. 12.10.2026 — R-4: subjects в /healthcheck отдаётся и при nats = off. Цена ошибки: низкая.
  5. 12.10.2026 — R-5: пароли MinIO/SMB в SecretStr не переводятся — вне запроса владельца; hide_input_in_errors всё равно скрывает их в ошибках валидации. Цена ошибки: пароли видны в repr(settings) до отдельной задачи.
  6. 12.10.2026 — R-6: маршрут — OpenSpec change nats-env-config в каждом из четырёх репозиториев, один план SDD на все четыре (больше пяти задач — SDD-контроллер). Цена ошибки: низкая, процессная.
  7. 12.10.2026 — R-7: e2e ядра не переводится на свои subject'ы (решение 7): ему нужен контейнер tabular-parser стенда на умолчаниях, а развести ядро теста и ядро стенда может только своя queue group, которая в этом change не настраивается. OQ-83 для make e2e остаётся открытым. Цена ошибки: перед make e2e по-прежнему останавливать ядро стенда.