Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Losing messages in case of connection interrupt #569

Open
Vera-Spoettl opened this issue Oct 24, 2024 · 1 comment
Open

Losing messages in case of connection interrupt #569

Vera-Spoettl opened this issue Oct 24, 2024 · 1 comment

Comments

@Vera-Spoettl
Copy link

Hi,

I'm trying to find the problem, why I sometimes lose messages. As it happens spuriously, I'm trying to understand it step by step. My first attempt is to make the connection as stable as possible. I'm afraid that this won't be the full solution but it would rule out connection problems.

Therefore, I built a very simple app that connects to my device and listens to the uptime topic (which is updated every second). Then I simulate a connection problem, by switching of the WiFi.
As you can see in the screenshot, I lose quite some messages during the connection problem.

Greenshot 2024-10-24 08 25 12

I initialized the MQTT client with the following parameters.

    /// Set keep alive to enable it.
    client.keepAlivePeriod = 15;

    /// The connection timeout period can be set.
    /// Timeouts < 1 sec will be set from the library to 5 seconds.
    client.connectTimeoutPeriod = 2000;

    /// Add the unsolicited disconnection callback
    client.onDisconnected = _onDisconnected;
    // Configure the disconnection timeout
    // Commented out as the setting has no effect if keep alive is disabled.
    // client.disconnectOnNoResponsePeriod = kMerlinMqttKeepAlive.inSeconds;

    /// Add the successful connection callback
    client.onConnected = _onConnected;

    // Set auto reconnect
    client.autoReconnect = true;

And from now on, I only work with assumptions and it would be great if you could tell me if they are correct or wrong:

  • the client tries to keep the connection alive for the 15 seconds. If there is no answer from the server, it disconnects.
  • when reconnecting I don't get the messages that where sent after the connection broke as I have configured the connection with cleanStart = true

If these assumptions are correct, I can understand why I'm losing messages.

What I don't understand is why I'm getting an exception when the client tries to reconnect:
Unhandled Exception: SocketException: Connection reset by peer (OS Error: Connection reset by peer, errno = 54), address = 192.168.50.1, port = 53731

Here is the fragment of the log file with the reconnect:

flutter: MQTTClient - PingCallback client callback - Client pinged
flutter: 1-2024-10-24 08:20:26.708116 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
flutter: 1-2024-10-24 08:20:41.709553 -- MqttConnectionKeepAlive::pingRequired
flutter: 1-2024-10-24 08:20:41.709619 -- MqttConnectionKeepAlive::pingRequired - sending ping request
flutter: 1-2024-10-24 08:20:41.709640 -- MqttConnectionHandlerBase::sendMessage - MQTTMessage of type MqttMessageType.pingRequest
Header: MessageType = MqttMessageType.pingRequest, Duplicate = false, Retain = false, Qos = MqttQos.atMostOnce, Size = 0

flutter: MQTTClient - PingCallback client callback - Client pinged
flutter: 1-2024-10-24 08:20:41.709847 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
flutter: 1-2024-10-24 08:20:41.715521 -- MqttConnectionBase::_onError - calling disconnected callback
flutter: 1-2024-10-24 08:20:41.716243 -- MqttConnectionHandlerBase::autoReconnect entered
flutter: MQTTClient - OnAutoReconnect client callback - Client is trying to reconnect
flutter: 1-2024-10-24 08:20:41.716474 -- MqttConnectionHandlerBase::autoReconnect - attempting reconnection
flutter: 1-2024-10-24 08:20:41.716542 -- MqttConnectionHandlerBase::connect - server 192.168.50.1, port 1883
flutter: 1-2024-10-24 08:20:41.716561 -- SynchronousMqttServerConnectionHandler::internalConnect entered
flutter: 1-2024-10-24 08:20:41.716577 -- SynchronousMqttServerConnectionHandler::internalConnect - initiating connection try 0, auto reconnect in progress true
flutter: 1-2024-10-24 08:20:41.716596 -- SynchronousMqttServerConnectionHandler::internalConnect - calling connectAuto
flutter: 1-2024-10-24 08:20:41.716743 -- MqttNormalConnection::connectAuto - entered
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Connection reset by peer (OS Error: Connection reset by peer, errno = 54), address = 192.168.50.1, port = 53731

flutter: 1-2024-10-24 08:20:54.668539 -- MqttServerConnection::_startListening
flutter: 1-2024-10-24 08:20:54.668640 -- SynchronousMqttServerConnectionHandler::internalConnect - connection complete
flutter: 1-2024-10-24 08:20:54.668663 -- SynchronousMqttServerConnectionHandler::internalConnect sending connect message
flutter: 1-2024-10-24 08:20:54.668682 -- MqttConnectionHandlerBase::sendMessage - MQTTMessage of type MqttMessageType.connect
Header: MessageType = MqttMessageType.connect, Duplicate = false, Retain = false, Qos = MqttQos.atMostOnce, Size = 21
Connect Variable Header: ProtocolName=MQTT, ProtocolVersion=4, ConnectFlags=Connect Flags: Reserved1=false, CleanStart=true, WillFlag=false, WillQos=MqttQos.atMostOnce, WillRetain=false, PasswordFlag=false, UserNameFlag=false, KeepAlive=15
MqttConnectPayload - client identifier is : Merlin639

flutter: 1-2024-10-24 08:20:54.668876 -- SynchronousMqttServerConnectionHandler::internalConnect - pre sleep, state = Connection status is connecting with return code of noneSpecified and a disconnection origin of none
flutter: 1-2024-10-24 08:20:54.672231 -- MqttConnection::onData
flutter: 1-2024-10-24 08:20:54.672295 -- MqttServerConnection::_onData - message received MQTTMessage of type MqttMessageType.connectAck
Header: MessageType = MqttMessageType.connectAck, Duplicate = false, Retain = false, Qos = MqttQos.atMostOnce, Size = 2
Connect Variable Header: SessionPresent={false}, ReturnCode={MqttConnectReturnCode.connectionAccepted}

Any help in understanding what's going on and how to get rid of the exceptions would be highly appreciated!

@shamblett
Copy link
Owner

OK, your points -

  1. the client tries to keep the connection alive for the 15 seconds. If there is no answer from the server, it disconnects.

2.when reconnecting I don't get the messages that where sent after the connection broke as I have configured the connection with cleanStart = true

Taking 2 first if you use clean start = true you will not get any retained messages as you have no session with the broker, if you do not clean start and use retained messages on reconnection you will get one message which will be the last one sent to your topic, i.e in your case your uptime topic, giving you the last know uptime state, then normal uptime messages will then resume.

1 is a little more complicated, the 15 seconds is not part of keep alive, from the log -

flutter: 1-2024-10-24 08:20:41.716743 -- MqttNormalConnection::connectAuto - entered
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Connection reset by peer (OS Error: Connection reset by peer, errno = 54), address = 192.168.50.1, port = 53731

flutter: 1-2024-10-24 08:20:54.668539 -- MqttServerConnection::_startListening

There is a 15 second gap between the raising of the exception and _startListening with no log output from the client, this is not the client doing this its the flutter runtime, why this is I don't know, after that you reconnect as normal.

Other users have reported this before occasionally, that's why the client catches this exception and continues during autoreconnect so as to try and step over this. You will use all messages in this gap of course

The autoreconnect sequence is not dependent on the keep alive mechanism between the client and the broker, you should be able to set client.keepAlivePeriod to any value you wish and the gap between the socket exception and reconnect will be whatever it happens to be in your use case, i.e. 15 seconds.

In general suddenly taking the network down does affect different platforms in different ways, the client is event driven and can only react to this, if the flutter runtime doesn't generate any events then the client can't react, hence it can get out of step with what's really happening.

Other users manage this by listening for these WIFI up/down events by using platform level events available to flutter then disconnecting the client manually on down events and reconnecting manually on up, autoreconnect is not enabled in these cases.

Autoreconnect is a last ditch fairly blunt instrument designed for sudden network failure not for known events like turning on/off your WIFI.

Hope this helps though this is a complicated area.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants