Files
IoT/doc/thinking/readiness-assessment-2026-10-05.md

11 KiB
Raw Permalink Blame History

Оценка готовности IoT к production (2026-10-05)

Три взгляда на один репозиторий: анализ A, анализ B и моё мнение. Все три — только чтением кода и документации, без сборки и запуска тестов (правила репо: команды — только через SSH на ВМ; сборку/прогоны не выполняли).


1. Анализ A (первый) — итог 5/10

Вердикт: цельный MVP, но по коду не считать production-ready для надёжной multi-tenant эксплуатации.

Блокеры

  • Не проверяется принадлежность namespace пользователю. Middleware проверяет JWT, но не передаёт sub обработчикам для сравнения с namespace из URL. CRUD и выдача пароля устройства берут namespace из запроса. Валидный токен не ограничивает пользователя его tenant-ом: auth.go:20, router.go:54, devices.go:179. exp фактически необязателен (auth.go:120).
  • Путь потери уже принятых сообщений. Flusher заменяет буфер на пустой ДО записи в PG, при ошибке только логирует. Consumer при этом удаляет сообщения из SQS после добавления в буфер: iot_telemetry_store.go:129, :135, consumer.go:81.
  • Health зелёный при остановившемся pipeline. Ошибки запуска bridge/consumer только логируются; горутина завершается, а /health всегда отдаёт ok: main.go:106, router.go:74.
  • Доставка допускает потери и дубли. Переполненная RAM-очередь bridge сбрасывает сообщения; исчерпание SQS-ретраев заканчивается drop. При at-least-once нет идемпотентного ключа против дублей: sender.go:70, :112.

Что хорошо

Компоненты сведены в понятный единый сервис; есть MQTT-reconnect с повторной подпиской, SQS-ретраи, graceful shutdown, разделение хранения устройств и телеметрии, широкий набор нагрузочных сценариев.

Чего не хватает до уверенного релиза

  • Автоматических Go-тестов (*_test.go не найдено) и CI.
  • Согласованности доков с кодом: гайд деплоя — iot-service:v0.1.2, Makefile — v0.1.13; loadtest README описывает уже исправленную блокировку MQTT-обработчика и visibility 30с, код задаёт 120с: deployment-nubes-production.md:3, Makefile:4, README.md:85, config.go:114.

2. Анализ B (второй) — итог ~60–65%

Вердикт: рабочий MVP / технический прототип, не продакшн-готовый сервис.

Что хорошо

  • Конвейер устройство → EMQX → мост → SQS → consumer → PG (per-tenant) работает end-to-end; подтверждено HISTORY и нагрузочными прогонами.
  • Прогоны: baseline 2390/2390 без потерь/дублей; ACL-нарушения отсекаются; reconnect-storm прошёл чисто.
  • Код небольшой (~2,4 тыс. строк в монолите), аккуратный: graceful shutdown, асинхронный SQS-диспатчер с ретраями, batch-insert, backoff, constant-time сравнение паролей.
  • Документация подробная: деплой без kubectl, интеграция с SQS, лог ревью и фиксов, 10 нагрузочных сценариев.
  • Auth и ACL в EMQX работают напрямую через PostgreSQL, без зависимости от монолита.

Что мешает назвать готовым

  1. Нет ни одного Go-теста и нет CI. Только Python-нагрузочные скрипты; в .github/ одни правила.
  2. Изоляция тенантов слабая. JWT проверяет только sub и exp; namespace из URL не сверяется с токеном. Без JWT_HMAC_SECRET подпись не проверяется. Любой «валидный» токен читает устройства и пароли любого namespace.
  3. Пароли устройств в БД открытым текстом и отдаются через GET. EMQX — password_hash_algorithm = plain.
  4. AUTH_TEST_MODE=true (любой Bearer) был включён на проде для диагностики. HISTORY §38 — «вернуть false»; закрытия не видно.
  5. /internal/mqtt/auth и /internal/mqtt/acl открыты на публичном порту без авторизации; дублируют PG-auth в EMQX и уже не нужны. ACL выдаёт права моста любому клиенту с clientid, совпадающим с мостовым.
  6. Нерешённая платформенная проблема: плавающий обрыв ответов >~15–64 КБ и WebSocket-обрывы ~150с; стабильного воспроизведения нет, разбор с DevOps идёт. В коде обходится пагинацией.
  7. Отложено: whitelist тенантских БД (любой namespace создаёт базу), DLQ, soak 24ч.
  8. Легаси не вычищено: cmd/iot-operator, controllers/, internal/api/, cmd/mqtt-bridge, cmd/sqs-consumer; в go.mod 12 строк k8s/controller-runtime; бинарники в bin/ и ws-probe/ws-probe. LEGACY.md обещает убрать после переписывания хендлеров, а оно сделано.
  9. Дрейф конфигурации: cookie = "iot-emqx-cookie-mvp" захардкожен в emqx.conf; параметры EMQX задаются только через env в deck-UI.
  10. Нет TLS-верификации к PG (verify_none). Нет rate limiting и метрик (только /health и admin-статистика).

Минимум для продакшна

  • привязать namespace к JWT, сделать JWT_HMAC_SECRET обязательным;
  • убедиться, что AUTH_TEST_MODE выключен;
  • хешировать пароли устройств или не отдавать повторно;
  • удалить /internal/mqtt/* и легаси;
  • добавить тесты и CI;
  • закрыть вопрос обрывов на платформе.

3. Моё мнение (перепроверено по коду)

Оба анализа компетентны и в главном совпадают. Расхождение 5/10 vs 60–65% — не в фактах, а в весе, который они дают одним и тем же находкам. Спорные места я перепроверил сам — оба правы по существу.

Подтверждается кодом (не предположение)

  1. Изоляция тенантов слабая — верно. middleware/auth.go проверяет JWT только на sub+exp; sub не сверяется с {namespace} (claims не передаются в обработчики, router.go не извлекает sub). exp необязателен (if claims.Exp > 0), без JWT_HMAC_SECRET подпись не проверяется.
  2. Путь потери принятых сообщений — верно. processTelemetry → InsertTelemetry кладёт в in-memory буфер и возвращает nil, после чего consumer безусловно удаляет сообщение из SQS. flushAll подменяет буфер на пустой ДО записи в PG и при ошибке только логирует. Данные могут молча пропасть.
  3. /health зелёный при упавшем pipeline — верно. main.go ошибки bridge/consumer только логирует; горутина завершается, healthHandler всегда отдаёт ok.
  4. Нет Go-тестов и CI — верно. *_test.go отсутствует, .github/ — правила.
  5. AUTH_TEST_MODE и пароли plaintext — верно и задокументировано (password_hash_algorithm=plain, AUTH_TEST_MODE=true для DevOps, §38).
  6. Дрейф доков — верно: гайд v0.1.2 vs Makefile v0.1.13; loadtest README 30с vs код 120с. Анализ A зафиксировал точнее.

Где анализ B точнее/дополняет

  • Явно оговорил, что сборку/тесты не запускал (ограничение правил — SSH).
  • Глубже разобрал открытые /internal/mqtt/*, TLS verify_none, захардкоженный cookie, невычищенное легаси и k8s-зависимости в go.mod.

Где я бы поправил обоих

  • Проценты условны. Оба дают один вывод «MVP/прототип, не production-ready»; цифры — риторика, а не измерение.
  • Приоритет блокеров: главные технические — потеря сообщений и tenant-граница. Plaintext-пароли и unauthed /internal/mqtt/* — важные, но второго эшелона (периметр платформы + EMQX уже на PG-auth напрямую снижают остроту).

Итог

Рабочий MVP, пригодный для демо/пилота, но не production-ready. Главные блокеры: слабая tenant-изоляция, гарантированная потеря сообщений при сбое flush, «слепой» health, отсутствие Go-тестов/CI и не закрытая платформенная проблема wss ~150с / MTU. Моя оценка — между A и B, ближе к «функционально готов, эксплуатационно — нет».