paho.mqtt.python icon indicating copy to clipboard operation
paho.mqtt.python copied to clipboard

State of client doesn't change to disconnected after connection lost

Open mohsen-mahmoodi opened this issue 4 years ago • 2 comments

When not using loop_forever or loop_start and running the loop in the main thread, a hard disconnect gets captured by the client but doesn't change the output of is_connected() method.

Steps to reproduce:

  1. Run an mqtt server, I use emqx:
docker run -d --name emqx -p 18083:18083 -p 1883:1883 emqx/emqx:v4.0.0
  1. Run the code below:
import time
import logging

import paho.mqtt.client as mqtt

logging.basicConfig(level=logging.DEBUG)

logger = logging.getLogger(__name__)


def on_connect(client, userdata, flags, rc):
    logger.debug('Connected with result code ' + str(rc))
    # subscribe
    client.subscribe('tienda/#')


def on_message(client, userdata, msg):
    logger.debug(msg.topic + " " + str(msg.payload))
    # if b'stop' in msg.payload:
    #     client.disconnect()


def on_disconnect(client, flags, rc):
    logger.debug('Disconnected with result code ' + str(rc))
    # client.reconnect()

# Build the client

client = mqtt.Client(clean_session=True)
logger.error('Client initialized with status: %s', client._state)
# Specify callback function
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
client.enable_logger(logger)
# client.username_pw_set('topse', 'cret')


# Establish a connection
client.connect('localhost', 1883, 60)
# wait for connection
while not client.is_connected():
    logger.debug('Connecting')
    client.loop(timeout=1)

logger.debug('Connected')

# This loops never ends even after there is no connection at all
while client.is_connected():
    client.loop()
    time.sleep(1)
    logger.debug('In main loop: %s', client.is_connected())
  1. browse http://localhost:18083/#/clients and find you client and disconnect it.

The result is that you will see the Disconnected with result code: 0 message, but the program never exits and keeps printing:

DEBUG:__main__:In main loop: True
DEBUG:__main__:In main loop: True
DEBUG:__main__:In main loop: True
DEBUG:__main__:In main loop: True
DEBUG:__main__:In main loop: True

The problem is the internal field _state doesn't changes to disconnected or any other states when we are not calling the disconnect method directly. This causes the is_connected() method return true and the loop never exits.

paho-mqtt version: 1.5.1

mohsen-mahmoodi avatar Nov 10 '20 22:11 mohsen-mahmoodi

Running the loop just like loop_forever() has no problem:

while True:
    rc = 0
    while rc == 0:
        logger.debug(client._state)
        rc = client.loop()
        time.sleep(2)

    try:
        client.reconnect()
    except (socket.error, OSError, WebsocketConnectionError):
        logger.error("Connection failed, retrying") 

The problem is that is_connected() returns wrong result.

mohsen-mahmoodi avatar Nov 11 '20 07:11 mohsen-mahmoodi

Possibly related to #441.

kpfleming avatar Nov 17 '20 12:11 kpfleming

I'm able to reproduce this with the sample code your provided and killing the broken after log of In main loop. I've used Mosquitto rather than emqx but this shouldn't matter.

#795 fix the issue in my test scenario.

PierreF avatar Jan 07 '24 14:01 PierreF