dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.41k stars 1.06k forks source link

How to reconnect properly #2060

Open naymore opened 1 month ago

naymore commented 1 month ago

This is what your best practice sample says:

    public static void Reconnect_Using_Timer()
    {
        /*
         * This sample shows how to reconnect when the connection was dropped.
         * This approach uses a custom Task/Thread which will monitor the connection status.
         * This is the recommended way but requires more custom code!
         */

        var mqttFactory = new MqttFactory();

        using (var mqttClient = mqttFactory.CreateMqttClient())
        {
            var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("broker.hivemq.com").Build();

            _ = Task.Run(
                async () =>
                {
                    // User proper cancellation and no while(true).
                    while (true)
                    {
                        try
                        {
                            // This code will also do the very first connect! So no call to _ConnectAsync_ is required in the first place.
                            if (!await mqttClient.TryPingAsync())
                            {
                                await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);

                                // Subscribe to topics when session is clean etc.
                                Console.WriteLine("The MQTT client is connected.");
                            }
                        }
                        catch
                        {
                            // Handle the exception properly (logging etc.).
                        }
                        finally
                        {
                            // Check the connection state every 5 seconds and perform a reconnect if required.
                            await Task.Delay(TimeSpan.FromSeconds(5));
                        }
                    }
                });

            Console.WriteLine("Press <Enter> to exit");
            Console.ReadLine();
        }
    }

I figured the ConnectAsync() method will always fail with "you cannot connect while already connected". So I need to wait for the Client to realize the connection has been dropped before I can reconnect.

There are two solutions to this.

  1. Check for client.IsConnected - but that kind of defeats the purpose of the whole TryPing thing. If I am not connected I don't need to ping because I know the ping will fail. If I am connected and the ping fails I need to wait for the client to realize this too before I can make any reconnection attempts.

  2. If the ping fails --> disconnect gracefully and start reconnecting immediately.

My preferred option would be this is handled by the library internally ;-) So I'll start looking at the ManagedClient as well.

Which project is your question related to?

naymore commented 1 month ago

Also in the WIKI the "event based approach" is recommended. Just saying... https://github.com/dotnet/MQTTnet/wiki/Client#reconnecting

SeppPenner commented 1 month ago

Also in the WIKI the "event based approach" is recommended. Just saying... https://github.com/dotnet/MQTTnet/wiki/Client#reconnecting

The wiki is for the old version (3.* and below only). Just saying. The samples are the way to go.