Closed MichalNemec closed 5 months ago
The exception you are getting is raised by the Dart/flutter runtime, not the client so the client can't really do much about this if it occurs.
Not sure why you are null checking the client above, you should be checking the connected state of the client, only if it indicates connected should you call disconnect, the use case here is connect, then either call disconnect or let the client handle an unsolicited disconnect from the network/broker after which you can call connect again. Don't connect while connected or disconnect while disconnected.
I'll need a client log to see exactly what is happening here.
Whats bothering me, that connection state change happens way late, this is what i have in app.dart
connectionChecker.instance.addNetworkStateChangedCallback((connected) async {
if (connected) {
MqttService().connect();
} else {
MqttService().disconnect();
}
});
Starts when i turn internet off
I/flutter ( 5181): 2024-03-10 16:39:21.374133 -- MqttConnectionBase::_onError - calling disconnected callback
I/flutter ( 5181): 2024-03-10 16:39:21.382589 -- MqttConnectionBase::_onDone - calling disconnected callback
I/flutter ( 5181): 2024-03-10 16:39:21.386489 -- MqttConnectionHandlerBase::autoReconnect entered
I/flutter ( 5181): 2024-03-10 16:39:21.391360 -- MqttConnectionHandlerBase::autoReconnect - attempting reconnection
I/flutter ( 5181): 2024-03-10 16:39:21.391518 -- MqttConnectionHandlerBase::connect - server mqtt.spiriway.com, port 8883
I/flutter ( 5181): 2024-03-10 16:39:21.391544 -- MqttSynchronousServerConnectionHandler::internalConnect entered
I/flutter ( 5181): 2024-03-10 16:39:21.391585 -- MqttSynchronousServerConnectionHandler::internalConnect - initiating connection try 0, auto reconnect in progress true
I/flutter ( 5181): 2024-03-10 16:39:21.391650 -- MqttSynchronousServerConnectionHandler::internalConnect - calling connectAuto
I/flutter ( 5181): 2024-03-10 16:39:21.392874 -- MqttServerSecureConnection::connectAuto - entered
I/flutter ( 5181): 2024-03-10 16:39:21.394311 -- MqttConnectionHandlerBase::autoReconnect entered
I/flutter ( 5181): [2024-03-10 16:39:21.448094 | Catcher 2 | INFO]
I/flutter ( 5181): [2024-03-10 16:39:21.448163 | Catcher 2 | INFO] ---------- ERROR ----------
I/flutter ( 5181): [2024-03-10 16:39:21.448305 | Catcher 2 | INFO] SocketException: Software caused connection abort (OS Error: Software caused connection abort, errno = 103), address = mqtt.spiriway.com, port = 41598
I/flutter ( 5181): [2024-03-10 16:39:21.448335 | Catcher 2 | INFO]
I/flutter ( 5181): [2024-03-10 16:39:21.448501 | Catcher 2 | INFO] ------- STACK TRACE -------
I/flutter ( 5181): [2024-03-10 16:39:21.453617 | Catcher 2 | INFO]
I/flutter ( 5181): [2024-03-10 16:39:21.454244 | Catcher 2 | INFO] ======================================================================
I/flutter ( 5181): [2024-03-10 16:39:21.455208 | Catcher 2 | INFO] Report result: true
I/flutter ( 5181): 2024-03-10 16:39:21.478634 -- MqttSynchronousServerConnectionHandler::internalConnect exception thrown during auto reconnect - ignoring
I/flutter ( 5181): 2024-03-10 16:39:21.478728 -- MqttSynchronousServerConnectionHandler::internalConnect - connection complete
I/flutter ( 5181): 2024-03-10 16:39:21.478749 -- MqttSynchronousServerConnectionHandler::internalConnect sending connect message
I/flutter ( 5181): 2024-03-10 16:39:21.478771 -- MqttConnectionHandlerBase::sendMessage - sending message started >>> -> MQTTMessage of type MqttMessageType.connect
I/flutter ( 5181): MessageType = MqttMessageType.connect Duplicate = false Retain = false Qos = atMostOnce Size = 1507
I/flutter ( 5181): ProtocolName = MQTT
I/flutter ( 5181): ProtocolVersion = 5
I/flutter ( 5181): ConnectFlags = CleanStart=false, WillFlag=false, WillQos=atMostOnce, WillRetain=false, PasswordFlag=true, UserNameFlag=true
I/flutter ( 5181): KeepAlive = 60
I/flutter ( 5181): Properties = Identifier : sessionExpiryInterval, value : 604800
I/flutter ( 5181): Will topic = null
I/flutter ( 5181): User name = user
I/flutter ( 5181): Password = pass
I/flutter ( 5181): 2024-03-10 16:39:21.487814 -- MqttConnectionHandlerBase::sendMessage - sending message ended >>>
I/flutter ( 5181): 2024-03-10 16:39:21.488158 -- MqttSynchronousServerConnectionHandler::internalConnect - pre sleep, state = Connection status is connecting with return code of success and a disconnection origin of none
I/flutter ( 5181): CONNECTION STATE CHANGE TO false
I/flutter ( 5181): 2024-03-10 16:39:21.556953 -- MqttConnectionHandlerBase::disconnect
I/flutter ( 5181): 2024-03-10 16:39:21.558667 -- MqttConnectionHandlerBase::_performConnectionDisconnect entered
I/flutter ( 5181): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5181): │ ⚠️ Disconnected from MQTT broker
I/flutter ( 5181): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
You seem to have auto reconnect enabled, if you are managing your own connect/disconnect sequence when you transit from online to offline turn this off.
You did however connect and send a connect message the broker then disconnected you before sending a connect ack.
If i do mqttServerClient.autoReconnect = false;
then when mqtt broker goes down, it would not try to reconnect, is that right?
Edit: implemented custom reconnect logic and it works amazingly, thank you for hints!
After further testing, on macos it works as intended, but on android (pixel 4 api 33), since its slower/different device, it still throws errors.
I/flutter ( 5899): 2024-03-10 23:38:18.095332 -- MqttConnectionBase::_onError - calling disconnected callback
I/flutter ( 5899): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5899): │ ⚠️ onDisconnected from MQTT broker
I/flutter ( 5899): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5899): 2024-03-10 23:38:18.122759 -- MqttConnectionBase::_onDone - calling disconnected callback
I/flutter ( 5899): 2024-03-10 23:38:18.123405 -- MqttClient::internalDisconnect - not invoking disconnect, no connection handler
I/flutter ( 5899): [2024-03-10 23:38:18.137733 | Catcher 2 | INFO] ============================== CATCHER 2 LOG ==============================
I/flutter ( 5899): [2024-03-10 23:38:18.137992 | Catcher 2 | INFO] Crash occurred on 2024-03-10 23:38:18.135962
I/flutter ( 5899): [2024-03-10 23:38:18.138043 | Catcher 2 | INFO]
I/flutter ( 5899): [2024-03-10 23:38:18.138082 | Catcher 2 | INFO] ---------- ERROR ----------
I/flutter ( 5899): [2024-03-10 23:38:18.138131 | Catcher 2 | INFO] SocketException: Software caused connection abort (OS Error: Software caused connection abort, errno = 103), address = mqtt.domain.com, port = 35242
I/flutter ( 5899): [2024-03-10 23:38:18.138165 | Catcher 2 | INFO]
I/flutter ( 5899): [2024-03-10 23:38:18.138198 | Catcher 2 | INFO] ------- STACK TRACE -------
I/flutter ( 5899): [2024-03-10 23:38:18.138700 | Catcher 2 | INFO]
I/flutter ( 5899): [2024-03-10 23:38:18.138758 | Catcher 2 | INFO] ======================================================================
I/flutter ( 5899): [2024-03-10 23:38:18.138949 | Catcher 2 | INFO] Report result: true
I/flutter ( 5899): CONNECTION STATE CHANGE TO false
how this can be solved for slower devices?
The client has no concept of fast or slow devices it just sits atop the Dart/flutter runtime in fact it is unaware what platform it is on so it cant help you with this.
There are many android users, see the closed issues, who are not reporting this, I suggest you maybe reach out to them or even to the flutter guys.
I notice you are using secure sockets, I wonder if different tls implementations could br causing this but again this is not a question for the client.
Thank you for your explanation, ill try to get this working by raising issue on dart-lang
Hello, i tried tcp 1883 user pass connection and its still throwing the socket exception, so its not only securesocket. I tried to setup basic rabbitMQ and use dart_amqp package and that goes without uncaught exception. It shows FatalException, but no crash.
@shamblett I had a bit of time and i was playing around with the library and i dont have the uncaught exception anymore.
its in mqtt_connection_base.dart
in _disconnect()
function. Ive changed it to this:
void _disconnect() async {
// On disconnect clean(discard) anything in the message stream
messageStream.clean();
if (client != null) {
try {
await client.done;
client.destroy();
client = null;
} catch (error) {
print("error");
}
}
}
since it has done
now with try catch
, i get double print of error, but no uncaught exception. I hope this is a good lead. Could you please make an update so that we can catch it in our code outside the package?
mqtt_connection_base is a base class for all connection types not just Socket based ones, Socket has a done() method Websockets in dart.io or dart.html don't so this will fail at run time in these environments.
Explain to me again what problem the exception is giving you, could you not just catch it yourself?
Always be mindful of effects on other environments and uers, for instance suddenly changing the client to propagate(or not) an exception may come as a surprise to some users, we don't want this.
mqtt_connection_base is a base class for all connection types not just Socket based ones, Socket has a done() method Websockets in dart.io or dart.html don't so this will fail at run time in these environments.
for universal_html that could be true, but in websocket i see done prop. https://api.dart.dev/stable/3.3.1/dart-io/WebSocket-class.html so it shows an option to do if client is specific type to do done call.
Explain to me again what problem the exception is giving you, could you not just catch it yourself?
I get connected to MQTT Broker properly. Then turn WIFI OFF on the device (in this testing case Pixel 4 api 33) and when i do that, _onDisconnected() callback is called and then i get UNCAUGHT exception. Since im using Catcher_2 package, when unhandled exception is thrown -> app shows dialog and i get email with this unhandled exception. I need to catch this exception, But dont know where. Based on this example, can you show me where exactly can i do try catch? https://github.com/shamblett/mqtt5_client/blob/master/example/mqtt5_server_client.dart
Just to sum it up:
Always be mindful of effects on other environments and uers, for instance suddenly changing the client to propagate(or not) an exception may come as a surprise to some users, we don't want this.
Every time when there is a new version of any package, i read changelog and breaking changes. 90% of the time its presented in the code as error or warning.
Now since i tried the socket.done and its caught properly, i dont believe its dart:io or dart:async issue. Also when i tested dart_amqp library, that didnt throw unhandled exception, so its handled properly in the library.
Comparing to amqp lib is of no use it's a server side lib any fix needs to incorporate browser(html) environments.
Other users deal with things like this(WiFi off, going into background etc.) by detecting this and calling disconnect on the client rather than waiting for the network failure to be reflected back to the client. This seems rather lazy, it is not an unsolicited failure, you know it's going to happen
Either way any fix must be for all environments.
You should be able to put a try catch block around your main function somehow also depending on your code you may be able to put the client in it's own zone.
Other users deal with things like this(WiFi off, going into background etc.) by detecting this and calling disconnect on the client rather than waiting for the network failure to be reflected back to the client. This seems rather lazy, it is not an unsolicited failure, you know it's going to happen
This is what im doing, but network changes after some time, so it happens late.
You should be able to put a try catch block around your main function somehow also depending on your code you may be able to put the client in it's own zone.
I wrapped whole connect function in runZoneGuaded and that worked, so finally this can be closed. Thank you for your ideas.
Hello, an amazing package to have, thank you!
I have slight problem when im testing online/offline in my app. Everything is working as intended, but when network changes, i do disconnect and still get this:
im using these settings
and upon network change i call this:
How can i disconnect when network goes offline and i dont get the error?