fix(mqtt): 修复 MQTT 连接反复断开重连的问题

- 协议从 MQTTv5 降级为 MQTTv311,提高兼容性
- client_id 添加随机后缀,防止多实例冲突导致互相踢连接
- 修复 on_connect/on_disconnect 回调的参数解析逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 11:43:15 +08:00
parent 08e9d785eb
commit b4fa6901f3

View File

@@ -4,6 +4,7 @@ MQTT 订阅服务
""" """
import json import json
import threading import threading
import uuid
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Callable, Dict, Any, Optional, List from typing import Callable, Dict, Any, Optional, List
@@ -59,20 +60,23 @@ class MQTTService:
return return
try: try:
# 给 client_id 添加随机后缀,防止多实例 client_id 冲突导致反复踢连接
unique_client_id = f"{settings.mqtt.client_id}_{uuid.uuid4().hex[:8]}"
# 兼容 paho-mqtt 1.x 和 2.x 版本 # 兼容 paho-mqtt 1.x 和 2.x 版本
try: try:
# paho-mqtt 2.0+ 新 API # paho-mqtt 2.0+ 新 API
self._client = mqtt.Client( self._client = mqtt.Client(
client_id=settings.mqtt.client_id, client_id=unique_client_id,
protocol=mqtt.MQTTv5, protocol=mqtt.MQTTv311,
callback_api_version=mqtt.CallbackAPIVersion.VERSION2 callback_api_version=mqtt.CallbackAPIVersion.VERSION2
) )
self._use_v2_callback = True self._use_v2_callback = True
except AttributeError: except AttributeError:
# paho-mqtt 1.x 旧 API # paho-mqtt 1.x 旧 API
self._client = mqtt.Client( self._client = mqtt.Client(
client_id=settings.mqtt.client_id, client_id=unique_client_id,
protocol=mqtt.MQTTv5 protocol=mqtt.MQTTv311
) )
self._use_v2_callback = False self._use_v2_callback = False
logger.info("使用 paho-mqtt 1.x 兼容模式") logger.info("使用 paho-mqtt 1.x 兼容模式")
@@ -124,11 +128,14 @@ class MQTTService:
"""连接回调 (兼容 1.x 和 2.x)""" """连接回调 (兼容 1.x 和 2.x)"""
# 1.x: (client, userdata, flags, rc) # 1.x: (client, userdata, flags, rc)
# 2.x: (client, userdata, connect_flags, reason_code, properties) # 2.x: (client, userdata, connect_flags, reason_code, properties)
rc = 0
if args: if args:
reason_code = args[-2] if len(args) >= 2 else args[-1] # 取倒数第二个参数1.x 的 rc 或 2.x 的 reason_code
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', reason_code) if len(args) >= 2:
else: reason_code = args[-2]
rc = -1 else:
reason_code = args[0]
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', 0)
if rc == 0: if rc == 0:
self._connected = True self._connected = True
@@ -149,12 +156,17 @@ class MQTTService:
# 1.x: (client, userdata, rc) # 1.x: (client, userdata, rc)
# 2.x: (client, userdata, disconnect_flags, reason_code, properties) # 2.x: (client, userdata, disconnect_flags, reason_code, properties)
self._connected = False self._connected = False
rc = 0
if args: if args:
reason_code = args[-2] if len(args) >= 2 else args[0] if len(args) >= 2:
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', reason_code) reason_code = args[-2]
logger.warning(f"MQTT 连接断开: {rc}") else:
reason_code = args[0]
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', 0)
if rc != 0:
logger.warning(f"MQTT 连接异常断开: rc={rc}")
else: else:
logger.warning("MQTT 连接断开") logger.info("MQTT 连接断开")
def _on_message(self, client, userdata, msg: mqtt.MQTTMessage): def _on_message(self, client, userdata, msg: mqtt.MQTTMessage):
"""消息回调""" """消息回调"""