hivemq / hivemq-mqtt-client

HiveMQ MQTT Client is an MQTT 5.0 and MQTT 3.1.1 compatible and feature-rich high-performance Java client library with different API flavours and backpressure support
https://hivemq.github.io/hivemq-mqtt-client/
Apache License 2.0
832 stars 153 forks source link

MqttClient does not update host/port properties when host is changed after a reconnect #538

Open oreillymj opened 2 years ago

oreillymj commented 2 years ago

Expected behavior

I would expect a client variable to reflect the host/port currently connected to after a reconnect.

Actual behavior

However, after a reconnect, where the host and port change, the client information still retains the original connection information.

To Reproduce

Create a client variable with scope outside of the creating function. Add functionality to switch between multiple hosts (broker A & B) in an onDisconnected event handler. Connect to Broker A, then force a failover to Broker B. Display the client information which shows Broker A connection info.

client.getState() still maintains the original connection information.

Steps

Reproducer code

private  Mqtt3AsyncClient client;

public void createclient(){
String[] serverHosts = {"192.168.0.1", "192.168.0.2"};

client = MqttClient.builder()
        .serverHost(serverHosts[0])
        .addDisconnectedListener(new MqttClientDisconnectedListener() {
            private int reconnects = 0;

            @Override
            public void onDisconnected(MqttClientDisconnectedContext context) {
                reconnects++;
                String nextHost = serverHosts[reconnects % serverHosts.length];
                context.getReconnector()
                        .reconnect(true)
                        .transportConfig().serverHost(nextHost).applyTransportConfig();
                if (reconnects % serverHosts.length == 0) {
                    context.getReconnector().delay(5, TimeUnit.SECONDS);
                }
            }
        })
        .build();

}

 public void connect(){
  client.connectWith()
                          .keepAlive(240)
                          .send()
                          .whenComplete((mqtt3ConnAck, throwable) -> {
                              if (throwable != null) {
                                  // handle failure
                                  Log.e(TAG,"connect->Connection Error",throwable);
                              } else {
                                  // setup subscribes or start publishing
                                  Log.d(TAG,"connect->Connected sucessfully without password");
                                  this.onConnect(client);
                              }
                          });

}

    void onConnect(final Mqtt3AsyncClient client) {
        MqttClientState state = client.getState();
        Log.i("onConnect->Client connected = " + state.isConnected());
        Mqtt3ClientConfig config= client.getConfig();
        Log.i("onConnect->Client connected to = " + config.getServerHost());
        Log.i( "onConnect->Client connected to = " + config.getServerPort());
        client
                .subscribeWith()
                .topicFilter(this.topic)
                .qos(MqttQos.AT_LEAST_ONCE)
                .callback(this::receive)
                .send()
                .whenComplete(
                        (subAck, throwable) -> {
                            if (throwable != null) {
                                Log.e(TAG,
                                        this.getClass().getSimpleName() + " identified by " + this.uuid + " failed to subscribe to topic " + this.topic + " ",
                                        throwable);
                            } else {
                                Log.i(TAG,
                                        this.getClass().getSimpleName() + " identified by " + this.uuid + " subscribed to topic " + this.topic + " and received " + subAck);
                            }
                        });

    }

Details

pglombardo commented 1 year ago

Hi @oreillymj - I see your point with this.

There is a lack of clarity between .serverHost(serverHosts[0]), client.getConfig() and an explicit call to .transportConfig().serverHost(nextHost).applyTransportConfig() that can definitely cause some confusion.

I'll have to give it some thought on how the API should better handle this.