Mqtt connect using MQTT agent

In our current software, we are managing MQTT operations using MQTT Agent on top of CoreMQTT library.
We were not sure how MQTT Agent manages MQTT disconnect scenarios and, therefore for now, we ourselves are managing MQTT connect initiation by calling MQTT_Connect() directly if we detect that no MQTT connection is established.
I understand we could have used MQTTAgent_Connect and let the MQTT Agent handle it on its own thread but what I am not sure is exactly how the agent handles when there is a sudden MQTT disconnect due to network going down or broker going away.
Does the agent come out of MQTTAgent_CommandLoop() on such cases after having cleaned up everything necessary(such as socket, connection, pending list, etc)?
I am not sure about the cleanup part but our experience is such that the command loop exits upon some disconnect scenarios.
Assuming this is the case, do we simply need to go back in with MQTTAgent_CommandLoop() after having called MQTTAgent_Connect()?
Does the agent automatically flush any Subscribe or Publish requests that may be on its queue but not flush Connect request and perform MQTT connect?
If you could kind of walk me through this process, that would be really awesome.
Regards,
James

Hi @jamesk,

I’d recommend against using MQTTAgent_Connect() for most cases as calling it doesn’t immediately form the MQTT connection, it adds only adds a command to do so at the end of the queue. That API is there to provide a thread-safe equivalent to MQTT_Connect(), and a counterpart to MQTTAgent_Disconnect(). However, you can just call MQTT_Connect() from the agent task, where you don’t have to worry about thread safety anyway as that’s the only task using coreMQTT APIs directly. In our demos we also just use MQTT_Connect() directly. This is from the documentation of MQTTAgent_Connect():

The MQTTAgent_Connect function is provided to give a thread safe equivalent to the MQTT_Connect API. However, it is RECOMMENDED that instead of the application tasks (i.e. tasks other than the agent task), the agent be responsible for creating the MQTT connection (by calling MQTT_Connect) before starting the command loop (with the MQTTAgent_CommandLoop() call). In that case, the agent SHOULD also be responsible for disconnecting the MQTT connection after the command loop has terminated (through an MQTTAgent_Terminate() call from an application task).

For your other questions,

I am not sure is exactly how the agent handles when there is a sudden MQTT disconnect due to network going down or broker going away.
Does the agent come out of MQTTAgent_CommandLoop() on such cases after having cleaned up everything necessary(such as socket, connection, pending list, etc)?

MQTTAgent_CommandLoop exits for three reasons:

  • Processing a DISCONNECT command
  • Processing a TERMINATE command
  • Any command returns any status code that is not MQTTSuccess.

When processing a command due to MQTTAgent_Terminate, the queue and pending ack list is cleared, but the MQTT connection is still active:

On command loop termination, all pending commands in the queue, as well as those waiting for an acknowledgment, will be terminated with error code MQTTRecvFailed.

For the other two cases, the queue and pending ack list are left as is, but the MQTT connection is or can assume to be disconnected. This is so that if a user decides to reconnect, the commands can still be processed without error, and QoS 1/2 publishes can be resent. If you instead want to clear the queue and pending ack list, you can do so explicitly with MQTTAgent_CancelAll

Does the agent come out of MQTTAgent_CommandLoop() on such cases after having cleaned up everything necessary(such as socket, connection, pending list, etc)?

The MQTT agent library has no knowledge of the socket, which is why it must exit after a DISCONNECT command, so the agent task can clean up the network connection.

Assuming this is the case, do we simply need to go back in with MQTTAgent_CommandLoop() after having called MQTTAgent_Connect()?

MQTTAgent_Connect() will add a command to the end of the queue, meaning every command currently in the queue will error. This is why I’d recommend using MQTT_Connect() followed by MQTTAgent_ResumeSession to reconnect the session immediately, before finally calling MQTTAgent_CommandLoop() again.

Does the agent automatically flush any Subscribe or Publish requests that may be on its queue but not flush Connect request and perform MQTT connect?

For resuming a session to be possible, nothing is cleared during an error. You should call MQTTAgent_ResumeSession() after calling MQTT_Connect() to clear the pending ack list if a session was not resumed with the broker.

To summarize, you probably want your code to look something like this:

Network_Connect( ... );
status = MQTT_Connect( ... );
if ( status == MQTTSuccess ) {
    status = MQTTAgent_ResumeSession( ... );
}

while( true ) {
    if( status == MQTTSuccess ) {
        status = MQTTAgent_CommandLoop( ... );
    }

    //MQTTAgent_CommandLoop() errored or terminated.
    if( status == MQTTSuccess ) {
        //Assuming we never use MQTTAgent_Disconnect, this is the
        //result of a termination. Just restart the loop as the
        //connection is still active.
    } else {
        //Error. Reconnect and restart the loop.
        Network_Disconnect( ... );
        Network_Connect( ... );
        status = MQTT_Connect( ... );
        if( status == MQTTSuccess ) {
            status = MQTTAgent_ResumeSession( ... );
        }
    }
}
1 Like