Files
SQS-service/MANUAL-NEXT-2026-10-08.md
T

170 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# МАНУАЛ: что делать дальше (состояние на 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) |