mqtthivemq

Hivemq Cloud - Persistent Session and Queuing Messages java vs android


I have a question / problem about Persistent Session and Queuing Messages. Here is the scenario: I have a publisher (java server) which is publish message and I have a receiver (android client). When android client it online it gets the messages which amazing, working very well. However, when I kill the android app and keep sending message from server and when I open android app, android does not receive previous messages.

Server side:


    final Mqtt5BlockingClient client = MqttClient.builder()
            .useMqttVersion5()
            .serverHost(host)
            .serverPort(8883)
            .sslWithDefaultConfig()
            .buildBlocking();

        // connect to HiveMQ Cloud with TLS and username/pw
        client.connectWith()
                .simpleAuth()
                .username(username)
                .password(UTF_8.encode(password))
                .applySimpleAuth()
                .noSessionExpiry()
                .cleanStart(false)
                .send();

        // This code is running every 15 sec
        String now = LocalDateTime.now().toString();
        String message = String.format("Hello: %s", now);
        // publish a message to the topic "my/test/topic"
        client.publishWith()
                .topic("hasan-device/sayHello")
                .payload(UTF_8.encode(message))
                .retain(true)
                .qos(MqttQos.AT_LEAST_ONCE)
                .noMessageExpiry()
                .send();

Client side:

        // create an MQTT client
        final Mqtt5BlockingClient client = MqttClient.builder()
                .identifier("my-device-1")
                .useMqttVersion5()
                .serverHost(host)
                .serverPort(8883)
                .sslWithDefaultConfig()
                .automaticReconnectWithDefaultConfig()
                .buildBlocking();

        // connect to HiveMQ Cloud with TLS and username/pw
        client.connectWith()
                .simpleAuth()
                .username(username)
                .password(UTF_8.encode(password))
                .applySimpleAuth()
                .noSessionExpiry()
                .cleanStart(false)
                .send();

        // subscribe to the topic "my/test/topic"
        client.subscribeWith()
                .topicFilter("hasan-device/sayHello")
                .retainHandling(Mqtt5RetainHandling.SEND)
                .send();

        // set a callback that is called when a message is received (using the async API style)
        client.toAsync().publishes(ALL, publish -> {
            byte[] message = publish.getPayloadAsBytes();
            LOGGER.info("Received message: {} -> {}, ", publish.getTopic(), new String(message, UTF_8));
        });

Expecting to message arrive when device back to online


Solution

  • When the Android app restarts with the persistent session, brokers will send down pending messages immediately. This can happen before the application callbacks get initialised.

    Here is an example from when I did some testing with this: messages before callbacks initialised

    To fix, move this bit of code to execute just before the connectWith call:

    // set a callback that is called when a message is received (using the async API style)
    client.toAsync().publishes(ALL, publish -> {
        byte[] message = publish.getPayloadAsBytes();
        LOGGER.info("Received message: {} -> {}, ", publish.getTopic(), new String(message, UTF_8));
    });