hivemq-mqtt-client icon indicating copy to clipboard operation
hivemq-mqtt-client copied to clipboard

How to turn off RECONNECT?

Open liuhuan0225 opened this issue 8 months ago • 1 comments

🐛 Bug Report

Cannot call disconnect in non-CONNECTED state Unable to stop automaticReconnect in Android Device hivemq-shaded = { group = "com.hivemq", name = "hivemq-mqtt-client-shaded", version = "1.3.5" }

🔬 How To Reproduce

Steps to reproduce the behavior:

  1. useMqttVersion3().automaticReconnect().initialDelay(1, TimeUnit.SECONDS).maxDelay(2, TimeUnit.SECONDS).applyAutomaticReconnect()
  2. Turn off device network and run HiveMQ
  3. disconnect() 提示 com.hivemq.client.mqtt.exceptions.MqttClientStateException: MQTT client is not connected.
  4. AutomaticReconnect will still be executed and cannot be stopped

liuhuan0225 avatar Apr 02 '25 11:04 liuhuan0225

I had the same issue, no way to stop reconnecting, even disconnect is not working in this case.

Please consider add an API for this case

Thanks in advance.

Hussein-Al-Zuhile avatar Jun 10 '25 07:06 Hussein-Al-Zuhile

A solution for this would be great. Mqtt3AsyncClient.disconnect() seems to be unusable with this issue.

fnordian avatar Oct 23 '25 14:10 fnordian

Hi all - thanks for reporting this! I'm talking with the team about a potential fix in #724. We'll have an update soon.

pglombardo avatar Oct 27 '25 10:10 pglombardo

Just an update that the team is a bit overloaded right now but we'll review that PR as soon as possible and make a decision.

In the meantime, feel to try that github branch (add-disconnect-gracefully) to validate that the solution works for you and provide feed back in #724.

I can't promise that it will go out in it's current state but the feedback would definitely be helpful.

That PR adds a new interface method disconnectGracefully that allows you to gracefully disconnect regardless of client state.

If there are any questions - let us know!

pglombardo avatar Oct 28 '25 12:10 pglombardo

Was able to test the PR, but it does not solve the issue fully since the new method doesn't stop the auto-reconnect if a connection was never established successfully.

Until the issue is resolved, I basically copied the auto-reconnect logic in a DisconnectedListener adding a short circuit flag for when it should stop attempting to reconnect. Hope this helps!

public class MqttHiveClientWrapper implements MqttClientDisconnectedListener {
    static final long RECONNECT_START_DELAY_NANOS = TimeUnit.SECONDS.toNanos(MqttClientAutoReconnect.DEFAULT_START_DELAY_S);
    static final long RECONNECT_MAX_DELAY_NANOS = TimeUnit.SECONDS.toNanos(MqttClientAutoReconnect.DEFAULT_MAX_DELAY_S);

    private Mqtt3AsyncClient hiveMqttClient;
    private boolean connectionActive = false;

    public void initClient() {
        this.hiveMqttClient = Mqtt3Client.builder()
                .addDisconnectedListener(this)
                .identifier(IDENTIFIER)
                .serverHost(HOST)
                .serverPort(PORT)
                .buildAsync();
    }

    public void connect() {
        this.connectionActive = true;
        if(this.hiveMqttClient != null && !this.hiveMqttClient.getState().isConnectedOrReconnect()) {
            this.hiveMqttClient.connect();
        }
    }

    public void disconnect() {
        this.connectionActive = false;
        if (this.hiveMqttClient != null) {
            this.hiveMqttClient.disconnect();
        }
    }

    @Override
    public void onDisconnected(@NotNull MqttClientDisconnectedContext context) {
        // Only attempt to reconnect if connect should be active
        if (this.connectionActive && context.getSource() != MqttDisconnectSource.USER) {
            final MqttClientReconnector reconnector = context.getReconnector();
            final long delay = (long) Math.min(RECONNECT_START_DELAY_NANOS * Math.pow(2, reconnector.getAttempts()), RECONNECT_MAX_DELAY_NANOS);
            final long randomDelay = (long) (delay / 4d / Integer.MAX_VALUE * ThreadLocalRandom.current().nextInt());
            reconnector.reconnect(true).delay(delay + randomDelay, TimeUnit.NANOSECONDS);
        }
    }
}

max-was-here avatar Nov 03 '25 16:11 max-was-here

It is a known inconvenience that the disconnect method can only be called when the client is connected but not when the client is trying to reconnect. The current solution is to implement a disconnected listener that stops reconnecting.

// create client together with a boolean setting that stops reconnect
final AtomicBoolean stopReconnect = new AtomicBoolean(false);
final Mqtt5Client client = Mqtt5Client.builder()
    // other client setup
    .automaticReconnectWithDefaultConfig()
    .addDisconnectedListener(context -> {
        if (stopReonnect.get()) {
            context.getReconnector().reconnect(false);
        }
    })
    .build();

// when you want to disconnect finally, set stopReconnect to true in addition to calling disconnect
stopReconnect.set(true);
client.toAsync().disconnect();

SgtSilvio avatar Nov 10 '25 11:11 SgtSilvio

@max-was-here nice for figuring out a workaround. You do not need to copy the auto-reconnect code. You can have another disconnected listener in addition to the auto-reconnect logic. See my comment above.

SgtSilvio avatar Nov 10 '25 11:11 SgtSilvio