eclipse / paho.mqtt.rust

paho.mqtt.rust
Other
511 stars 102 forks source link

client.disconnect() does not disconnect the client if no connection #214

Open RockyGitHub opened 8 months ago

RockyGitHub commented 8 months ago

Hello!

I've been trying to do some logic involving the AsyncClient and calling disconnect().

I am seeing consistently that that after calling client.disconnect().wait_timeout(), when there is no internet connection, a subsequent call to client.is_connected() returns true. Not until the client times itself out, outside of the call to disconnect().

Is this intended?

Thank you! -Rocky

fpagliughi commented 8 months ago

Definitely not the _desired_behavior.

Did the disconnect .wait_timeout() actually timeout? Or did it succeed or otherwise fail with an error? If it timed out or otherwise failed, then, internally, it might not have figured out that it is off-line. Yet.

Also was this done with Ethernet (hardwired) or WiFi (wireless). With wireless, it seems like if usually takes a long time for the OS to tell the app that the connection was lost.

Either way on all that, I have gotten a few reports that is_connected() is returning the wrong result. Mostly like you say: It's claiming to be connected when it's not. This is mostly an upstream library issue, but I'll dig into it and report it upstream.

RockyGitHub commented 8 months ago

The wait_timeout() does indeed timeout, it fails with an error since it doesn't get a server response in this particular case.

This was on WiFi. It does take a while for the client to realize it has lost connection, I figured this was due to my default keep_alive setting at 60s.

Yeah I don't think it's your library, fortunately or unfortunately lol. However, the call to disconnect() immediately calls the message_callback with the None value, so I can work with that to avoid using the client.is_connected(). It's certainly a lot less convenient though. But thank you for providing the callback functionality :)

btw, the way I am mocking a loss of internet connection is by doing sudo ip route add mqtt.ip.address via 127.0.0.1 and then I restore it with sudo ip route del mqtt.ip.address

fpagliughi commented 8 months ago

Yeah, it can be difficult for any network application, especially if the OS never tells it that the interface or network is down. It can be even worse for Cell and Satellite modems, which I used to use a lot for MQTT.

The KeepAlive is a failsafe for these occasions. If the underlying TCP connection is jammed up, the one way you know for sure that you still have a connection to the server is to send a request and get a proper response. But remember that the requested keep alive (60sec, in your case) is the time at which the client should send the ping request (PINGREQ), but I'm pretty sure it's up to the client to decide how long to wait for the response (PINGRSP) before declaring the connection lost and shut it down.

On the broker side, it expects to get a packet from the client within the keep alive time that that particular client requested. But fairly universally (as per the MQTT spec), the server will wait an additional 50% of the requested time (90sec total in your case) before declaring the client lost and closing the connection.