Subscription could be lost if loop is started before connecting to server. (inconsistiency in docs)
Prerequisites
Note: You may remove this section prior to submitting your report.
A small team of volunteers monitors issues. Please help us to help you by making it simple to understand and, if possible, replicate your issue. Prior to reporting a bug please:
- [x] Test the latest release of the library.
- [x] Search existing issues.
- [x] Read the relevant documentation.
- [x] Review your server configuration and logs.
- [ ] Consider testing against a different server (e.g. mqtt.eclipseprojects.io or test.mosquitto.org)
- [x] If possible, test using another tool (e.g. MQTTX / mosquitto_sub) to confirm the issue is specific to this client.
- [ ] If you are unsure if you have found a bug, please consider asking on stackoverflow for a quicker response.
Bug Description
According do docs:
It is acceptable to firstly launch event loop before connecting.
Connect to a remote broker. This is a blocking call that establishes the underlying connection and transmits a CONNECT packet. Note that the connection status will not be updated until a CONNACK is received and processed (this requires a running network loop, see loop_start, loop_forever, loop…).
But according to examples (like client_sub ) the order is opposite.
mqttc.on_subscribe = on_subscribe
# Uncomment to enable debug messages
# mqttc.on_log = on_log
mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)
mqttc.subscribe("$SYS/#")
When I tried to start loop before connecting I had problems with connection and with subscription.
Reproduction
- Run simple MQTT broker
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx:5.0.20
- Run code
import time
import paho.mqtt.client as mqtt
def on_connect(mqttc, obj, flags, reason_code, properties):
print("reason_code: " + str(reason_code))
def on_message(mqttc, obj, msg):
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
def on_subscribe(mqttc, obj, mid, reason_code_list, properties):
print("Subscribed: " + str(mid) + " " + str(reason_code_list))
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.loop_start() ### LOOP STARTED BEFORE CONNECTION
mqttc.connect("localhost", 1883, 60)
print("Is connected: ", mqttc.is_connected())
mqttc.subscribe("/#")
while True:
time.sleep(1)
- Send something to on thread
/logsusing tool like MQTTX - Subscription does not work (messages are not printed)
$ python3 ./example.py
Is connected: False
reason_code: Success
Replacing order in this code
mqttc.connect("localhost", 1883, 60)
mqttc.loop_start() ### LOOP STARTED AFTER CONNECTION
Fixes the issue:
$ python3 ./example.py
Is connected: False
reason_code: Success
Subscribed: 1 [ReasonCode(Suback, 'Granted QoS 0')]
/logs 0 b'{\n "msg": "xxxxxxxxx"\n}'
Environment
- Python version: 3.10
- Library version: 2.0
- Operating system (including version): Ubuntu 22.04
- MQTT server (name, version, configuration, hosting details): (check repro)
Logs
I reproduce your issue and this should either be fixed in code (preferred) or documented.
I've updated the title, since starting the loop before work and the connection works (cf your reason_code: Success message) but the subscribe() is indeed lost. You should be able to see that subscribe() is lost because it return an error (but no example show error checking).
Regardless of this bug, it might be preferable to subscribe in the on_connect callback to be sure your subscription is kept in case of reconnection (I'm not sure the broker had to persist them, especially when clean_session is True - the default). e.g.
def on_connect(mqttc, obj, flags, reason_code, properties):
print("reason_code: " + str(reason_code))
mqttc.subscribe("/#")