From 3b0815155a3b1deaa5956153fef3c02cca8fe8ed Mon Sep 17 00:00:00 2001 From: Repinoid Date: Thu, 8 Oct 2026 17:33:03 +0300 Subject: [PATCH] =?UTF-8?q?doc:=20=D0=BC=D0=B0=D0=BD=D1=83=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=B0=20=E2=80=94=20=D1=81=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=BE=D1=8F=D0=BD=D0=B8=D0=B5,=20=D1=80=D0=B5=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F,=20=D0=BF=D0=BB=D0=B0=D0=BD=20=D1=88=D0=B0?= =?UTF-8?q?=D0=B3=D0=BE=D0=B2=20(=D0=92=D0=9C=20->=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=B1=D0=B8=D0=B5=D0=BD=D0=B8=D0=B5=20->=20=D1=85=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=BB=D0=B8=D1=89=D0=B5),=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D0=B4=D1=8B,=20=D0=B3=D1=80=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8,=20=D0=BA=D0=B0=D1=80=D1=82=D0=B0=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MANUAL-NEXT-2026-10-08.md | 169 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 MANUAL-NEXT-2026-10-08.md diff --git a/MANUAL-NEXT-2026-10-08.md b/MANUAL-NEXT-2026-10-08.md new file mode 100644 index 0000000..7d62bc9 --- /dev/null +++ b/MANUAL-NEXT-2026-10-08.md @@ -0,0 +1,169 @@ +# МАНУАЛ: что делать дальше (состояние на 2026-10-08) + +> Файл для НОВОГО чата. Прочитай его первым, затем документы из раздела 2. +> Репозиторий: `/home/naeel/nubes/SQS_und_IoT/SQS-service` (сервис `shared-sqs`). +> Всё, что описано как «сделано», уже в ветке `main` и на сервере (`origin/main`). + +--- + +## 1. Где мы сейчас + +**Код SQS готов и запушен.** Ветка `main` = `origin/main`, рабочая копия чистая. + +Что сделано за 2026-10-05…08: +- закрыт весь план доработок P0/P1/P2 (`doc/thinking/plan-for-flash-2026-10-05.md`); +- P1.2 — индексация сообщений (tombstone + индексы + амортизированная компакция); +- полный код-ревью сервиса + исправления (утечка блокировки очереди, DLQ в батче, + гонка лимита тенантов, потеря `NubesSub`, общий HTTP-клиент); +- интеграционные прогоны: `api_test.sh` 22/22, `sdk_test.py` 15/15, `fifo_dlq_probe.py` — PASS, + стресс 3×2000 сообщений — без зависаний. + +**Прод-сервис никто не использует** (podтверждено владельцем), IoT переделывается с нуля. +Поэтому мы свободны менять архитектуру без обратной совместимости. + +## 2. Документы, которые надо прочитать в этом порядке + +| Документ | Что внутри | +|---|---| +| `doc/thinking/architecture-analysis-2026-10-08.md` | **ГЛАВНЫЙ**: решения по размещению и разбиению (публичный SQS, обход через ВМ, модульный монолит data-plane/control-plane) | +| `doc/thinking/nubes-large-body-workaround-findings-2026-10-08.md` | как та же болезнь платформы обойдена в `~/nubes/drhider` (буфер на ВМ, pull вместо push) — со ссылками «файл:строка» | +| `doc/thinking/nubes-workaround-applicability-to-sqs-2026-10-08.md` | применимость к SQS: 4 варианта, обязательные замеры, техусловия (Host для подписи, внешние `QueueUrl`, TLS) | +| `HISTORY/2026-10-07-session-log.md` | журнал правок: что и почему менялось, найденные дефекты, уроки | +| `doc/thinking/nubes-ticket.md` | исходная диагностика сетевой болезни (MSS/MTU + таймер шлюза). **Тикет отправлять не нужно** — см. `HANDOFF-NEW-CHAT.md`, раздел 7 | +| `doc/thinking/plan-for-flash-2026-10-05.md` | исходный план доработок (выполнен) | +| `HANDOFF-NEW-CHAT.md` | доступы, креды, конфигурация кластера, история проекта | + +## 3. Принятые решения (не пересматривать без причины) + +1. **SQS — публичный сервис**, как AWS SQS / YMQ. Внешний доступ обязателен, + совместимость с AWS SDK — обязательна. +2. **Сетевую болезнь платформы не «лечим» тикетом** — обходим: публичная точка входа + на ВМ, минуя managed-шлюз. +3. **Пока — ВМ (сейчас `5.172.178.213`), потом отдельная прод-ВМ.** Девопсов не дёргаем, + пока не отлажено; затем — уже с доказательствами (tcpdump, период 31–33 с, MSS 1448). +4. **«Без монолитов» = модульный монолит**: в отдельные процессы выносим только то, + что живёт по-разному. Для SQS граница одна: **data-plane** (очереди/сообщения/SigV4) + и **control-plane** (тенанты, креды, админ). Биллинг/метрики/UI — модули, не сервисы. +5. **Ограничение, которое важнее разбиения**: ядро очередей держит состояние в памяти + одного пода → одиночка. Пока хранилище не вынесено, «не монолит» ≠ «масштабируется». + +## 4. План работ (порядок обязателен) + +### Шаг 1. Проверить гипотезу на ВМ — БЕЗ кода (критерий входа: домен и сертификат) +Цель: убедиться, что на ВМ болезни нет, **до** вложений в разбиение. + +1. Собрать бинарник: `make build` (или `CGO_ENABLED=0 go build -o shared-sqs ./app/cmd/`). +2. Поднять на ВМ (memory-only достаточно): см. команды в разделе 5. +3. Поставить nginx с TLS на выбранный домен, проксировать на `127.0.0.1:4100`. + **Обязательно** `proxy_set_header Host $host;` — иначе AWS-подпись не сойдётся + (сервис берёт хост из запроса: `app/auth/auth_middleware.go:315-317`). +4. Замерить **с внешней машины** (не с ВМ): малые тела, 1 КБ, 10 КБ, 100 КБ, 256 КБ, + плюс длинный прогон на таймауты. Инструменты: `tests/tcp_mtu_probe.py`, + `tests/long_compare_local.py`, `tests/compare_ymq_vs_shared.py`. +5. **Критерий успеха:** 0 зависаний ~51 с, 0 таймаутов 31–33 с. + +Если гипотеза не подтвердится — СТОП, вернуться к разбору (раздел 2, документ о применимости). + +### Шаг 2. Код: разбиение на два процесса +- `data-plane` — SQS API и очереди (`app/gosqs/*`, `app/router/router.go`, `app/auth/auth_middleware.go`). +- `control-plane` — админка (`app/admin/admin.go`) и управление тенантами (`app/tenant/*`). +- Что уже учитывать при разбиении: + - адреса очередей формируются жёстко: `app/gosqs/tenant_helpers.go:29-37` → + `http://{region}.{host}:{port}/{tenantID}/{queue}`; хост/порт только из `app/conf/goaws.yaml` + (`app/conf/config.go:87-90`), env-переменных для Host нет → **внешние `QueueUrl` потребуют правки**; + - подпись SigV4 считается по заголовку `Host` (см. выше); + - ключ очереди — `{accessKey}:{queueName}` (`app/gosqs/tenant_helpers.go:15`). + +### Шаг 3. Код: вынести состояние (стратегический пункт) +- Сейчас: память — источник истины, Redis — write-through (`app/persistence/redis.go`, + `LoadAllQueues`), восстановление при старте. +- На ВМ поставить Redis и решить, как читать: остаться write-through или перейти к Redis + как источнику истины (тогда появится возможность нескольких экземпляров). +- Это решение определяет потолок сервиса (сейчас — один под). + +### Шаг 4. IoT — отдельно, после SQS +- Внешний MQTT-канал неизбежен (устройства), но там только мелкая телеметрия; + критичен разрыв wss ~150 с (лечится переподключением). +- Крупные тела устройств через managed-шлюз не пускать (лимит/дробление/приём на ВМ). +- IoT переделывается с нуля не монолитом: bridge (MQTT), consumer (→storage), API. + +## 5. Команды (проверены) + +**Локальный запуск (memory-only, без Redis):** +```bash +cd /home/naeel/nubes/SQS_und_IoT/SQS-service +go build -o /tmp/shared-sqs ./app/cmd/ +SHARED_SQS_SEED_DEMO=true /tmp/shared-sqs --admin-token=dev-token-123 --port=4100 +# креды демо-тенанта печатаются в лог при старте +``` +⚠️ Не запускать через `| head` — SIGPIPE убивает процесс на середине теста. + +**Проверки кода:** +```bash +go build ./... && go vet ./... && go test -race ./app/... +``` + +**Деплой на ВМ:** +- зеркало репозитория: `naeel@5.172.178.213:~/terra/SQS-service`; +- SSH: `ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213`; +- ⚠️ порт **443 на 213 занят** (nginx/xray/hysteria), поэтому публичная точка SQS — + отдельный домен на существующем nginx (виртуальный хост/SNI) или отдельный порт; +- ⚠️ в образе `Dockerfile` зашит `REDIS_ADDR` внутреннего кластера — на ВМ переопределить + (или не задавать, чтобы работать memory-only). + +**Сборка образа (если через Docker):** `make docker-build` (`Makefile`, образ `naeel/shared-sqs`). + +## 6. Грабли и правила (не наступать повторно) + +1. `app/cmd` в `.gitignore` → при добавлении файлов `git add -f app/cmd/...`. +2. `deployments/` в этом репозитории **нет** — не искать. +3. `Queue.Messages` — tombstone-хранилище: менять только через `AppendMessage`/`RemoveIndex`/ + `Compact`/`Reset`; число живых = `queue.LiveCount()`, а НЕ `len(queue.Messages)` + (`app/models/models.go`). +4. После `GetLocked`/`GetRLocked` — `defer Unlock` **до** любых `return` (иначе очередь + зависает навсегда; было в `receive_message.go`, исправлено). +5. Интеграционные тесты: `tests/api_test.sh` читает `ENDPOINT`, python-тесты — `ENDPOINT_URL`. + `boto3` в системе нет (PEP 668) → скачать колеса `pip download boto3`, распаковать в `/tmp` + и запускать с `PYTHONPATH`. +6. Лимит очередей тенанта = 10 → после упавших прогонов чистить очереди. +7. Диагностика зависаний сервиса: стек горутин по `kill -QUIT` (SIGQUIT). +8. Правки ingress на платформе — только через `ShturvalServiceConfig` (kubectl откатывает ArgoCD). + +## 7. Правила работы с владельцем (обязательные) + +- Коммитить после каждой логически завершённой правки; **пуш — только по прямой команде**. +- Документировать всё, включая собственные ошибки (HISTORY + `doc/thinking/`). +- Не выполнять `terraform apply`/`destroy`, не менять платформу, не удалять инстансы. +- Не расширять область работ; не лезть в соседние репозитории без прямой команды. +- Рекомендация без замера — не рекомендация, а догадка: сначала мерить, потом предлагать. +- Вопрос от владельца = только ответ (ничего не делать, пока не последует команда). + +## 8. Открытые вопросы (нужны решения владельца) + +1. **Домен и сертификат** для публичной точки SQS на ВМ (порт 443 занят → виртуальный хост?). +2. **Отдельная прод-ВМ** — когда создавать и с какими параметрами (пока хватит 213 для тестов; + хватит ли 213 — проверить замером: ядра, память, диск, загрузка). +3. **Redis на ВМ** — ставить сейчас или пока memory-only. +4. **Вынос состояния** (Шаг 3) — когда начинать; это определяет масштабируемость. +5. **Клиенты без явного `endpoint_url`** — есть ли такие (влияет на внешние `QueueUrl`). + +## 9. Карта кода (что где) + +| Путь | Ответственность | +|---|---| +| `app/cmd/goaws.go` | точка входа, флаги, загрузка конфига, periodic tasks, HTTP-сервер | +| `app/router/router.go` | HTTP-роутинг, лимит тела 3 МБ, биллинг/метрики по операциям | +| `app/auth/auth_middleware.go` | SigV4 (header + presigned), извлечение тенанта | +| `app/auth/jwt.go`, `app/auth/cache.go` | валидация JWT через внешний API + кэш | +| `app/gosqs/*` | SQS-операции (send/receive/delete/visibility/queue/attributes/tags) | +| `app/gosqs/receive_message.go` | long-polling, выдача сообщений (в т.ч. per-queue лок) | +| `app/gosqs/gosqs.go` | фоновый тик: retention, дедупликация, видимость, DLQ | +| `app/models/models.go` | `Queue`/`SqsMessage`, индексация (tombstone), FIFO-состояние | +| `app/models/globals.go` | `SyncQueues`: map очередей + tenant-индекс + блокировки | +| `app/persistence/redis.go` | write-through в Redis, загрузка при старте, переподключение | +| `app/admin/admin.go` | админка (тенанты/очереди/сообщения), UI-API по JWT | +| `app/tenant/tenant_store.go` | хранилище тенантов, генерация кредов, авто-провижининг по JWT | +| `app/billing/billing.go` | учёт операций в PostgreSQL (воркер + буфер) | +| `app/metrics/*` | Prometheus-метрики и gauge-обновление | +| `app/conf/goaws.yaml` | Host/Port/Region, дефолты очередей (используется для URL) | +| `tests/*` | интеграционные проверки (aws CLI, boto3, пробы сети/MTU) |