fix: review findings (async SQS dispatcher, backoff, batch insert, shutdown order, pagination, HMAC) + loadtest fixes; v0.1.6

This commit is contained in:
“Naeel”
2026-08-16 18:24:09 +04:00
parent 090cedca67
commit 3fedf9317c
27 changed files with 581 additions and 122 deletions
+61
View File
@@ -1117,3 +1117,64 @@ paho connect() rc=0 даже при CONNACK≠0 (on_connect обязателен
### 31.4 Дальше
- Ждём «делай» по фиксам из 31.1 (минимум №1 и №2 перед большими нагрузками).
- Прогон полных сценариев — по команде.
---
## 32. Фиксы ревью внедрены (v0.1.6) + нагрузочные прогоны (17:00 GMT+03)
### 32.1 Внедрённые фиксы (код)
| # | Что | Где |
|---|---|---|
| 1 | Асинхронный SQS-диспатчер: канал 10000 + 4 worker'а, ретраи 1/2/4с, дроп при переполнении | bridge/sender.go (новый), handler.go, bridge.go |
| 2 | VisibilityTimeout 120с (config дефолт + Dockerfile + env на деплойменте) | config.go, Dockerfile |
| 3 | Backoff (1с→60с, x2) при ошибках обработки PG | consumer.go |
| 4 | Shutdown: bridge+consumer → flush → HTTP последним | main.go |
| 5 | Батч-INSERT (100 строк / 200мс flusher, final flush в Close) | iotpg |
| 6 | Disconnect(2000) вместо 250мс при остановке | bridge.go |
| 7 | (whitelist tenant-БД) — ОТЛОЖЕНО, отдельная фича | — |
| 8 | Пулы: devices 20 (env IOT_PG_MAX_CONNS), admin 10 | store/open.go, iotpg |
| 9 | JWT: опциональная HS256-проверка (env JWT_HMAC_SECRET) | middleware/auth.go |
| 10 | Close rows вместо defer в цикле | iotpg AdminStats |
| 11 | Пустое SQS-body: лог + удаление из очереди | consumer.go |
| 12 | Валидация топика (ns/deviceID непустые, "telemetry") | bridge/handler.go |
| 13 | CREATE USER: проверка роли + QuoteIdentifier/QuoteLiteral (не Sprintf) | iotpg |
| 14 | Валидация MQTT_BROKER_URL (ws:// или wss://) | config.go |
| 15 | generateMQTTPassword: 3 попытки crypto/rand | handler/devices.go |
| 16 | Баг DO-блока: параметры $n в DO недопустимы (найден прогоном) | iotpg |
| 17 | Пагинация: List limit/offset; telemetry limit+offset | devices.go, telemetry.go, iotpg |
| 18 | Admin-пул 10 | iotpg |
| 19 | Лог битого JSON — уже был | — |
| 20 | Subscribe-таймаут/ошибка → принудительный реконнект | bridge.go |
| + | Оversize >250KB → явный дроп с логом (лимит SQS 256KB) | sender.go |
| + | Гонка getTenantDB → per-ns мьютекс | iotpg |
### 32.2 Баги, всплывшие при выкатке
- DO-блок с $n-параметрами («got 2 parameters but statement requires 0») —
старые сообщения крутились с backoff; исправлено (32.1 №16).
- Зеркало платформы кэширует теги: повторный push v0.1.3 не подтянулся
(rollout restart) → правило: КАЖДОЕ изменение = НОВЫЙ тег (v0.1.4).
- SQS-лимит 256KB: 300KB-сообщения дропались SendMessage 400
(InvalidParameterValue) → явный пре-чек 250KB + документировано.
- Шлюз платформы рвёт ответы API >~15КБ (эмпирика: limit=50 OK 15KB/0.27с,
limit=200 завис на 15.6KB) → добавлен offset в API, верификатор ходит
страницами по 50; large-payload верификация только по логам consumer.
### 32.3 Результаты нагрузочных прогонов (прод, GMT+03)
| Сценарий | Итог |
|---|---|
| baseline 20 уст-в × 2 msg/s × 60с | sent 2390, delivered 2390, lost 0 (среди sent), dup 0; p50 466мс / p95 785мс / p99 1486мс |
| burst x5, 20с | sent_high 1958, delivered 1948, dup 0, recovery 112.3с; латентность пика p50 17.4с |
| large-payload 200KB | доставка по логам consumer: 6/6 сохранено, oversize-дропов 0 |
| reconnect-storm 30с-циклы, 120с | 30 форс-реконнектов, 1191/1191, dup 0 |
| multitenant 5 тенантов | first-msg: p50 1376мс / p95 3085мс (создание БД) |
| acl-violation | 11/11 чужих публикаций разорвали сессию, accepted 0 |
| auth-neg | rc=4 / rc=5 (отказы) |
| api-crud 5×10 | POST/GET/DELETE p50 ~240-255мс, 0 ошибок |
| telemetry-query 5×20 | 17.1 rps, p50 241мс, 0 ошибок |
### 32.4 Версии и артефакты
- iot-service v0.1.6 (digest 5868e9481cfd) + latest — задеплоен.
- loadtests: API-ретраи (3×), парсинг 204-пустого тела, offset-пагинация,
burst считает по фактическому sent, large-payload без API-верификации.
- Repo-память: /memories/repo/iot.md (факты платформы, правила деплоя).
- ОТЛОЖЕНО: tenant-whitelist (#7), DLQ в shared-sqs, soak 24ч.