mqtt5_client icon indicating copy to clipboard operation
mqtt5_client copied to clipboard

Getting 'Bad State' exception when disconnecting a connection in mid auto-reconnect

Open kmiller15211 opened this issue 5 months ago • 4 comments

I have a situation where I am creating a websocket IoT connection to AWS via Cognito credentials. I have auto reconnect, and resubscribeOnAutoReconnect set to true, keepalive set to 5 seconds.

I have a scenario where, when I get new AWS Cognito credentials (due to the activity token expiring, or the wifi goes off and then back on again, etc.), I want to stop the old connection, and start a new one with the new AWS Cognito credentials. What is happening is that the old connection is in the background trying to autoreconnect. So, even though I call disconnect() on the old connection, when that connect call completes and it tries to run the code in mqtt_connection_handler_base.dart that follows, it gets the following exception:

The exception: "Bad state: Cannot add new events after calling close" The throwing source: ...mqtt5_client-4.5.0/lib/src/connectionhandling/mqtt_connection_handler_base.dart

Tracing through the timeline:

  • I'm connected with connection A, and everything is happy.
  • I turn wifi off and wait for a bit for the connection to go down.
    • Connection A detects the loss of keepalive heartbeats, it goes into it's autoreconnect state.
  • I turn wifi back on.
  • My code detects the wifi state is on again, and regenerates cognito credentials - callbacks are called to notify clients of this.
  • The code that's managing the IoT connections gets this callback and reacts by trying to create a brand new connection:
    • It then calls disconnect() on connection A, and stops the listener of the connection A stream
    • It creates a brand new IoT connection, connection B, with new Cognito credentials and connects
    • Connection B connects, starts listening, etc. Everything with Connection B is happy.
  • Eventually, Connection A's autoreconnect call (to connect()) times out, and then it goes to this else case in mqtt_connection_handler_base:
    connectionStatus = await connect(server, port, connectionMessage);
    autoReconnectInProgress = false;
    if (connectionStatus.state == MqttConnectionState.connected) {
        [REDACTED]
    } else {
      MqttLogger.log(
          'MqttConnectionHandlerBase::autoReconnect - auto reconnect failed - re trying');
      clientEventBus!.fire(MqttAutoReconnect());
    }

It is here where I believe it's trying to fire on the clientEventBus, and since the connection has been disconnected/closed, it's going down.

This results in an unhandled exception. It's not causing any major issues (like a tree falling in the forest where there's no one around to hear it), but I'd like to clean this up, if possible.

Maybe this line: clientEventBus!.fire(MqttAutoReconnect()); should use a "?" instead of a "!" so that it quietly fails instead of throws? Or maybe there's some other API that I'm not seeing that I can call to allow connection A to finish cleaning up before creating B (undesirable, as I don't want to block for seconds)?

Thank you in advance. Sorry if this isn't following some GitHub etiquette, I haven't entered many issues.

TLDR Details: Deploying/running on an Android Pixel 7 Building with Android Studio Koala 2024.1.1 Patch 1 Using the MQTT 5 library, version: mqtt5_client: ^4.5.0

kmiller15211 avatar Sep 05 '24 13:09 kmiller15211