架構決策 (ADR)
IoT Simulator 每個模擬裝置使用獨立 WebSocket + 狀態 in-memory
Context
IoT Simulator Admin Console 需要支援同時模擬多個裝置,Admin UI 要即時看到每個裝置的狀態與 MQTT 訊息。 需要決定通訊架構(單一 WebSocket vs 多路 vs polling)以及 session 狀態的持久化方式(DB vs in-memory)。
Decision
結論(通訊):每個模擬裝置使用獨立的 WebSocket 連線,同時承載控制命令(client → server)和 MQTT 事件(server → client)。
結論(持久化):Simulator session 存在 SimulatorManager._sessions dict in-memory,不寫入 DB。
Alternatives Considered
通訊方案:
- 單一 WebSocket + message type multiplexing — 考慮過。多裝置共用單一 WS 需在協議層加裝置 ID routing,邏輯複雜,前端訂閱過濾也難做。
- HTTP polling — 考慮過。MQTT 事件實時性要求高(heartbeat 每秒),polling 延遲不可接受。
持久化方案:
- DB 持久化 simulator session — 考慮過。simulator 是 dev-only 工具,DB 寫入增加不必要的 schema 複雜度;backend 重啟後 session 自然失效是可接受行為(開發環境)。
- Redis 短期持久化 — 考慮過。增加依賴,收益僅為「backend 重啟後 session 存活」,對 dev tool 不值得。
Consequences
好:
- 每個裝置的 WebSocket 連線天然隔離,前端可針對單一裝置訂閱事件
- In-memory session 零 DB 依賴,適合 dev/testing 環境使用
- 前端 WebSocket 重連時自動建立新 session,行為直觀
壞 / 代償:
- Backend 重啟後所有 simulator session 消失(設計上接受此限制)
- 前端需處理 WebSocket 斷線 reconnect 邏輯
asyncio.Lock必須保護每個 session 防止 WS 命令與 MQTT event handler 並發競爭
中性:
- Hybrid command routing:lifecycle 命令(pair/remove/reset)在 SimulatorEngine 直接處理;device control 命令(pause/resume/volume)可透過 MQTT round-trip 測試完整流程
- Sleep timer、volume 等命令在 WebSocket handler 做 input validation(非負數、0-100 範圍)