Files
IoT/HISTORY/2026-10-11-session-log.md
T

52 lines
4.2 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-11 (IoT: внешнее код-ревью и фиксы)
> Запись по требованию «документировать всё, включая собственные ошибки» (приказ 2026-09-24).
> Предыдущие: `HISTORY/2026-10-07-session-log.md`, `HISTORY/2026-10-10-session-log.md`.
> Основание: внешнее ревью Claude Sonnet по промпту `../CLAUDE-REVIEW-PROMPT.md`
> (40 пунктов на два сервиса; SQS-часть — в `SQS-service/HISTORY/2026-10-11-session-log.md`).
## 1. Задача
Разобрать находки ревью по монолиту `iot-service` и исправить их.
## 2. Что исправлено
### 🔴 Критичные
- **🔴8/🔴9 — poison-строка в `flushAll`** (`internal/storage/iotpg/iot_telemetry_store.go:166,177`).
При постоянной (не retryable) ошибке `flushAll` возвращал ошибку → consumer
(`consumer.go:159`) не удалял батч из SQS → бесконечный redelivery всего батча.
Теперь ошибку ставит только retryable-ветка; постоянная ошибка означает «валидные
строки уже вставлены построчно, битые отброшены» → `Flush` возвращает nil, батч
подтверждается. Коммит `1fe543f`.
### 🟡 Важные
| Пункт | Файл | Суть | Коммит |
|-------|------|------|--------|
| 🟡13 | `bridge/sender.go` | Ретраил бесконечно любые ошибки SQS; permanent (4xx/размер/нет очереди) занимали воркеры → классификация `isPermanentSQSErr` (smithy APIError) | `657850d` |
| 🟡14 | `bridge/handler.go` | `MessageID = uuid` на каждый колбэк → повторная QoS1-доставка не дедуплицировалась. Теперь `SHA256(ns\|device\|topic\|payload)` | `657850d` |
| 🟡15 | `bridge/bridge.go` | После 3 неудач подписки ждали следующего реконнекта (которого не будет при живом соединении) → бесконечный ретрай подписки | `657850d` |
| (new) | `bridge/handler.go` | Defense-in-depth: валидация формата `ns`/`deviceID` из топика (барьер — EMQX authz) | `657850d` |
| 🟡17 | `consumer/consumer.go` | `receiveCount` проверялся только для битого envelope → применяем `maxReceiveCount` ко всем ошибкам | `5114320` |
| 🟡18 | `cmd/iot-service/main.go` | `run()` выходил до завершения `server.Shutdown` → deferred Close срабатывали до дренажа in-flight. Добавлен `shutdownDone` | `5114320` |
| 🟡19 | `api/handler/devices.go` | Ошибка `GetByName` после успешного INSERT давала 500 (пароль терялся, повтор → 409) → отдаём 201 с in-memory объектом | `5114320` |
| 🟡11 | `iotpg/iot_telemetry_store.go` | `getTenantDB`/`QueryTelemetry` не проверяли `safeNamespaceRe` (`a_b` ↔ `a-b` → одна БД) → валидация на всех путях | `f41a9fe` |
### Осознанно НЕ менялось (решения)
- 🟡16 (QoS1 ack): оставлен async-ack + метрика дропов (throughput важнее; синхронный
ack блокировал бы MQTT-колбэк — это уже чинили ранее).
- 🟡12 (`AUTH_TEST_MODE`): уже fail-closed — при отсутствии `JWT_HMAC_SECRET` и
`AUTH_TEST_MODE=false` middleware отказывает в обслуживании.
## 3. Прочее (перед ревью, в этой же сессии)
- `193509c` — консоль: namespace = `sub` (убрали `sless-{SHA256}`, расходившийся с
middleware) и удалили несуществующий `POST /v1/namespaces/{ns}/ensure`.
## 4. Верификация
- `go build ./...`, `go vet ./...`, `go test -race ./...` — зелёные.
- Push: `54fe1f5..f41a9fe` в `origin/master`.