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

4.2 KiB

Журнал сессии — 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.