# МАНУАЛ: что делать дальше (состояние на 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) |