From e98a9239bf4b0968d38cca6528b46d6a2eeaaf4d Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 4 Oct 2026 06:16:59 +0400 Subject: [PATCH] =?UTF-8?q?docs(dev):=20README=20=E2=80=94=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D1=8C=D1=8E=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B8=205.3=20(T3?= =?UTF-8?q?.3=E2=80=93T3.6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - T3.3: риск общих queue group подтверждён чтением тестов tabular-parser и scan-gateway (test_roundtrip, боевые *.request); тесты arm-core изолированы (временная БД, уникальный subject результатов); команда проверки подписчиков. - T3.4: «Остаточные тома» — down -v только с --profile services. - T3.5: GET / отвечает 307 на // и затем 404. - T3.6: up -d --build <сервис> пересоздаёт сервис и зависимости: arm-core-migrate пересоздаётся вместе с arm-core, scan-emulator со scan-gateway — нет (проверено). Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2 --- dev/README.md | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/dev/README.md b/dev/README.md index 8d2eccb..168ecf7 100644 --- a/dev/README.md +++ b/dev/README.md @@ -110,8 +110,9 @@ curl -s -X POST localhost:8000/api/v1/dev/token -H 'Content-Type: application/js curl -s localhost:8000/api/v1/me -H "Authorization: Bearer " # email, роли KA_RF, права ``` -Образ `arm-core` содержит только бэкенд: фронт (`web/`) в `Dockerfile` не собирается, `GET /` отвечает 404. UI — -`npm run dev` из `../../arm-core/web` (см. README `arm-core`). +Образ `arm-core` содержит только бэкенд: фронт (`web/`) в `Dockerfile` не собирается. `GET /` отвечает **307** с +редиректом на `//`, а тот — 404 (`curl -L` показывает 404 на `http://127.0.0.1:8000//`; редирект на `//` — особенность +`arm-core`, вынесена в его follow-up). UI — `npm run dev` из `../../arm-core/web` (см. README `arm-core`). **Ожидание готовности и коды возврата `--wait`** (compose 2.34, проверено 2026-10-04): @@ -124,12 +125,22 @@ curl -s localhost:8000/api/v1/me -H "Authorization: Bearer " # email, Для скриптов указывайте долгоживущие сервисы явно — форма не зависит от состава профиля. -**Пересборка после изменения кода сервиса:** `docker compose --profile services up -d --build` (или -`up -d --build <сервис>`). Образ `arm-core:dev` собирает только сервис `arm-core`, образ `scan-gateway:dev` — только -`scan-gateway`; `arm-core-migrate` и `scan-emulator` используют готовый тег (`pull_policy: never`): две сборки одного -тега давали разные ID образа, и каждый следующий `up` пересоздавал контейнеры. Поэтому `arm-core-migrate` или -`scan-emulator` в одиночку (`up -d scan-emulator`) на машине без образа не стартуют — сначала соберите его -(`docker compose --profile services build scan-gateway`) или поднимайте профиль целиком. +**Пересборка после изменения кода сервиса:** `docker compose --profile services up -d --build` — пересобирает образы +и пересоздаёт все контейнеры, чей образ сменился. Образ `arm-core:dev` собирает только сервис `arm-core`, образ +`scan-gateway:dev` — только `scan-gateway`; `arm-core-migrate` и `scan-emulator` используют готовый тег +(`pull_policy: never`): две сборки одного тега давали разные ID образа, и каждый следующий `up` пересоздавал контейнеры. +Поэтому `arm-core-migrate` или `scan-emulator` в одиночку (`up -d scan-emulator`) на машине без образа не стартуют — +сначала соберите его (`docker compose --profile services build scan-gateway`) или поднимайте профиль целиком. + +Форма `up -d --build <сервис>` пересоздаёт только сервис и его зависимости (проверено 2026-10-04 на образе, +пересобранном с `--no-cache`): + +| Команда | Что пересоздано | Что осталось на старом образе | +|---|---|---| +| `up -d --build arm-core` | `arm-core` и `arm-core-migrate` (он — зависимость `arm-core`, миграции нового кода выполняются) | — | +| `up -d --build scan-gateway` | только `scan-gateway` | **`scan-emulator`** (не зависимость шлюза) — до следующего `docker compose --profile services up -d`, который его пересоздаёт | + +После правок кода `scan-gateway`, затрагивающих эмулятор, пересобирайте профиль целиком. **Остановка и сброс профиля** — только с `--profile services`: без него compose не видит контейнеры профиля (см. «Сброс окружения»). @@ -238,10 +249,18 @@ postgres nats minio`, затем `make test-integration` (или `make check-ful эмулятор ИС Сканирование поднимается в процессе интеграционного теста; контейнер `scan-emulator` профиля `services` тестами не используется. Общее описание проверок — [`checks.md`](checks.md). -> **Не запускайте интеграционные тесты при поднятом профиле `services`** (не проверялось, вывод из устройства обмена): -> контейнеры подписаны на те же subject'ы общего NATS в тех же queue group (`arm-core` на `recognition.result`, -> `tabular-parser` и `scan-gateway` на свои `*.request`), поэтому NATS может отдать сообщение теста контейнеру, а не -> экземпляру из теста. Перед тестами: `docker compose --profile services stop arm-core tabular-parser scan-gateway scan-emulator`. +> **Не запускайте интеграционные тесты `tabular-parser` и `scan-gateway` при поднятом профиле `services`.** Их +> сквозные тесты (`api/tests/integration/test_roundtrip.py`, у `scan-gateway` ещё `test_nats_minio_integration.py`) +> публикуют запросы в боевые `recognition.tabular.request` / `recognition.image.request`, а экземпляр сервиса из теста +> подписан в ту же queue group (`tabular-parser` / `scan-gateway`), что и контейнер. NATS отдаёт каждое сообщение группы +> одному подписчику — запрос теста может уйти контейнеру, и тест упадёт по таймауту ожидания ack (так прямо сказано в +> docstring теста `scan-gateway`). Риск подтверждён чтением кода тестов, тесты при поднятом профиле не запускались. +> Интеграционные тесты `arm-core` от контейнеров изолированы: временная БД на сессию (рабочая `armka` не используется) +> и уникальный subject результатов на тест. Перед тестами сервисов: +> `docker compose --profile services stop tabular-parser scan-gateway scan-emulator`; проверить, что чужих подписчиков +> нет: `curl -s 'http://127.0.0.1:8222/subsz?subs=1' | grep -o '"subject": *"recognition[^"]*"'` — строк +> `recognition.tabular.request` / `recognition.image.request` быть не должно (`recognition.result` — подписка контейнера +> `arm-core`, тестам `arm-core` не мешает). ## Проверка контракта @@ -274,5 +293,6 @@ postgres nats minio`, затем `make test-integration` (или `make check-ful отдельности: образ ещё не собран — `docker compose --profile services build` (см. «Профиль `services`»). - **`minio-init` завис или завершился с ошибкой:** `docker compose logs minio-init`; чаще всего `minio` не стал healthy — `docker compose logs minio`. Повторный `docker compose up -d` идемпотентен. -- **Остаточные тома от прошлых запусков** (старый пароль БД, бакет не тот): `docker compose down -v` и запуск заново. +- **Остаточные тома от прошлых запусков** (старый пароль БД, бакет не тот): `docker compose --profile services down -v` + и запуск заново (без `--profile services` контейнеры профиля и том `hotfolder` остаются, см. «Сброс окружения»). - **`up -d --wait` возвращает код 1:** см. раздел «Запуск инфраструктуры» — указывайте сервисы явно.