doc(HISTORY): архитекторский разбор телеметрии — 5 проблем и решение

This commit is contained in:
Repinoid
2026-10-07 07:38:27 +03:00
parent b6c083e80f
commit 2b3838680f
+34
View File
@@ -79,5 +79,39 @@
(вычистить легаси `internal/api/`, `cmd/sqs-consumer`). (вычистить легаси `internal/api/`, `cmd/sqs-consumer`).
- Платформенные проблемы (wss ~150с, MSS/MTU) — вне кода. - Платформенные проблемы (wss ~150с, MSS/MTU) — вне кода.
---
## Архитекторский разбор (Дипсик Про, по итогам перепроверки)
Перечитана цепочка `bridge → SQS → consumer → iotpg` целиком. Найдены 5 проблем
(часть — мой же недочёт при кодинге P0-7/P0-8):
1. 🔴 **Залипание на «ядовитом» батче.** После моего фикса «возвращаем строки в
буфер при ошибке» один payload, падающий не по `ON CONFLICT`, зацикливает
flush этого namespace навсегда (flusher каждые 200мс). Так «тихая потеря»
превратилась в «вечное залипание». ← моя ошибка: фикс без различения типов ошибок.
2. 🔴 **Битый envelope теряется безвозвратно.** `processTelemetry` на битый JSON
возвращает `nil` → consumer подтверждает (DeleteMessage) → мусор исчезает без
следа. Если мусор шлёт bridge по багу — данные теряются навсегда, без DLQ.
3. 🟠 **Нарушение порядка телеметрии.** `ts` ставится `now()` в БД при INSERT, а
не в момент приёма (`ReceivedAt` из envelope не идёт в батч). При батчинге и
нескольких потоках порядок для device_id не гарантирован.
4. 🟠 **Дублирование / нет дедупа для `message_id=""`.** `ON CONFLICT` по
`(device_id, message_id)` не ловит NULL: legacy `cmd/sqs-consumer` передаёт
`""` → дубли вставляются. Плюс гонка InsertTelemetry(full) ↔ flusher на одном
namespace = два параллельных INSERT.
5. 🟡 **Close() может потерять последний батч** при ошибке shutdown-flush
(`_ = flushAll(...)` — ошибка игнорируется).
### Решение (как принято)
- п.1 + п.3 (битые/ядовитые → DLQ) — делаю я (Дипсик Про), это дизайн-развилки.
- п.2 + п.4 (ReceivedAt; message_id NOT NULL) — передаются Флашу, с критериями.
- Битое сообщение — **в DLQ** (стандартный паттерн: valid→process, invalid→DLQ).
- Ядовитый SQL-батч — различать retryable (сеть/PG лежит → ретрай в буфер) от
permanent (нарушение constraint → не вешать namespace, выброс в лог/DLQ).
### Статус
Реализация п.1 (разделение ошибок flush) и п.3 (ббитые → DLQ) — см. ниже.
## Проверки ## Проверки
- `go build ./...` и `go vet ./internal/...` — зелёные на каждом шаге. - `go build ./...` и `go vet ./internal/...` — зелёные на каждом шаге.