Bỏ qua để đến nội dung

Đầu vào MQTT dừng hoặc lỗi

Một datasource dựa trên MQTT đang truyền dữ liệu, và có gì đó bị gãy:

  • Suy luận tự chuyển từ đang chạy sang idle/lỗi — không ai bấm Stop.
  • Dự đoán trả về NaN, hoặc bảng điều khiển không hiện gì hợp lý.
  • Sink đầu ra MQTT báo lỗi ghi, với lý do như transport: not connected.
  • Một ánh xạ tag bị từ chối lúc lưu với thông báo tag_outside_subscription_*.
  • Test Connection hoặc Enable thất bại hoàn toàn trước khi có bất kỳ luồng nào chạy.

MQTT là một giao thức push — suy luận pull một mẫu mỗi tick từ một cache mà adapter điền vào khi message đến. Mỗi nguyên nhân dưới đây thực chất là cùng một câu hỏi nhìn từ góc khác: cache có nhận được một giá trị dùng được gần đây không?

Năm chế độ lỗi khác biệt cùng chia sẻ tập triệu chứng này. Grep log backend để phân biệt chúng — tất cả các ví dụ dưới đây chỉ hiện mã lỗi/lý do, không bao giờ hiện nội dung payload hay thông tin xác thực.

Terminal window
docker compose -f docker-compose.release.yml logs backend | grep -iE "MqttAdapter|ChannelReadException|channel .* read failed|tag stale|disconnected|not connected"
  1. Topic cũ (stale) (publisher chậm hoặc đã chết). Một cảnh báo xuất hiện trước khi lỗi:

    MqttAdapter tag stale: tag=<topic> age=<age> staleAfter=<window>
    Channel <index> (<tag>) read failed — stopping inference
    Inference fault: <reason>

    Cửa sổ hết hạn của cache là clamp(50 / SamplingHz, 5s, 60s)5 giây ở mức mặc định 10 Hz. Một topic publish chậm hơn cửa sổ đó sẽ hết hạn và gây ra ChannelReadException, mà runtime xử lý giống hệt một cảm biến đã chết: nó dừng suy luận thay vì đưa cho mô hình một giá trị đông cứng.

  2. Sentinel NaN / Infinity. Bộ phân tích payload MQTT chỉ chấp nhận các số hữu hạnNaN, Infinity, -Infinity, và một literal tràn số như 1e400 đều bị từ chối trước khi chúng đến được cache. Một thiết bị publish sentinel “không có phép đo” theo cách này không bao giờ làm mới giá trị đã cache của nó, nên nó hết hạn và lỗi theo đúng cách giống hệt như nguyên nhân 1 ở trên — cùng dòng log, cùng ChannelReadException. Theo thiết kế, không có chế độ lỗi riêng “NaN đã đến được mô hình” — điều đó sẽ âm thầm đầu độc mọi dự đoán downstream thay vào đó.

  3. Trục xuất client id (eviction). Tìm:

    MqttAdapter disconnected (SessionTakenOver); reconnecting

    hoặc, ở phía đầu ra, một lần ghi thất bại với:

    transport: not connected

    Các broker MQTT trục xuất kết nối đang giữ chỗ khi một client thứ hai kết nối với cùng một client id. Trên bản build hiện tại, điều này chỉ xảy ra khi: hai datasource cùng vai trò (hai đầu vào, hoặc hai đầu ra) chia sẻ một Client ID tường minh, hoặc một client MQTT bên ngoài dùng lại id đã cấu hình của một datasource.

  4. Tag nằm ngoài Base Topic đã đăng ký. Lưu một ánh xạ tag (hoặc bật datasource) thất bại ngay lập tức với:

    tag_outside_subscription_<tagRef>

    Adapter đầu vào chỉ đăng ký các tag đã ánh xạ của nó (hoặc wildcard Base Topic đã cấu hình) — một đường dẫn topic nằm ngoài phạm vi đó bị từ chối ngay lúc lưu thay vì âm thầm không bao giờ tạo ra một lần đọc.

  5. Lỗi kết nối ở cấp socket. Test Connection hoặc Enable thất bại trước khi bất kỳ luồng nào bắt đầu, với một trong các mã:

    connect_failed không thể tới / bị từ chối / lỗi DNS   timeout lần thử kết nối bị hủy trước khi hoàn tất

    Log backend xác nhận điều này bằng thời gian đã trôi qua và loại exception:

    MqttAdapter connect failed: broker=<broker> elapsedMs=<ms> errorType=<type>
  1. Topic cũ / sentinel NaN (nguyên nhân 1–2). Sửa nhịp publish, hoặc dừng nó publish một sentinel không hữu hạn, rồi bật lại datasource — một lỗi kéo runtime xuống idle, nên phục hồi không tự động:

    • Xác nhận khoảng publish thực tế của topic đã ánh xạ và so sánh nó với cửa sổ hết hạn ở Sampling Hz đã cấu hình của datasource.
    • Nếu topic báo cáo hợp lệ là “không có phép đo”, hãy chuyển thiết bị/gateway sang đơn giản là không publish trong khoảng thời gian đó thay vì gửi NaN/Infinity — cả hai được xử lý giống hệt nhau (một topic im lặng), nên không có lợi ích gì khi gửi sentinel.
    • Bật lại datasource (nạp lại mô hình, kết nối lại adapter), rồi bấm Start.
  2. Trục xuất client id (nguyên nhân 3). Đặt một giá trị khác biệt cho mỗi datasource cùng vai trò (hai đầu vào, hoặc hai đầu ra) đang chia sẻ một Client ID tường minh, hoặc xóa trống trường đó để MQTTnet tự sinh một id duy nhất cho mỗi bên. Nếu một client bên ngoài đang dùng lại id của datasource của bạn, hãy đổi một trong hai. Điều này không áp dụng cho một cặp đầu vào/đầu ra được xây từ cùng một cấu hình — hậu tố vai trò của v1.28.0 (-in/-out) đã giữ cho chúng không xung đột, không cần chỉnh sửa.

  3. Tag ngoài phạm vi đăng ký (nguyên nhân 4). Hoặc mở rộng Base Topic của datasource để bao phủ đường dẫn topic của tag, hoặc sửa đường dẫn topic của tag để nằm trong Base Topic hiện tại. Lưu lại ánh xạ.

  4. Lỗi socket (nguyên nhân 5). Xác minh host, port, và khả năng tới được của mạng từ bên trong container backend — không phải từ desktop của bạn. Đổi localhost thành tên container/service của broker (hoặc host.docker.internal từ một container tới Docker host), rồi thử lại Test Connection.

  • Kiểm tra khoảng publish của mọi topic đã ánh xạ so với cửa sổ hết hạn trước khi bật một đầu vào MQTT mới — giảm Sampling Hz để nới rộng ngưỡng chịu đựng (1 Hz → 50s) nếu một topic hợp lệ publish chậm.
  • Không bao giờ dùng lại một Client ID tường minh giữa hai datasource cùng vai trò (hai đầu vào, hoặc hai đầu ra), và đừng dùng lại Client ID của một datasource cho một client MQTT bên ngoài. Một cặp đầu vào/đầu ra trên cùng một cấu hình đã an toàn sẵn — v1.28.0 tự động thêm hậu tố cho mỗi bên (-in/-out).
  • Giới hạn Base Topic chặt chẽ theo đúng các tag bạn thực sự ánh xạ, và chỉ ánh xạ các tag có đường dẫn topic đã nằm trong đó.
  • Đừng mã hóa “không có dữ liệu” thành NaN/Infinity trên đường truyền. Một thiết bị im lặng khi không có gì để báo cáo hoạt động giống hệt và dễ suy luận hơn một giá trị sentinel.
  • Chạy Test Connection từ góc nhìn của box, không phải từ máy trạm của bạn — một broker có thể tới được từ desktop qua localhost có thể hoàn toàn không tới được từ container backend.