shashank created CAMEL-25944:
--------------------------------

             Summary: camel-paho-mqtt5 / camel-paho - the consumer sets its 
callback after connecting, so messages the broker sends for a kept session 
right after CONNACK are dropped (MQTT 5 QoS 2: lost)
                 Key: CAMEL-25944
                 URL: https://issues.apache.org/jira/browse/CAMEL-25944
             Project: Camel
          Issue Type: Bug
          Components: camel-paho, camel-paho-mqtt5
            Reporter: shashank
            Assignee: shashank


{{PahoMqtt5Consumer.doStart}} and {{PahoConsumer.doStart}} (main 9f839f4bcc9d) 
connect the client they created and only then call {{setCallback}}. When the 
client connects to a session that the broker kept, the broker sends the 
messages it queued for that session right after CONNACK, before Camel 
subscribes. A kept session is camel-paho-mqtt5 with {{cleanStart=false}} and a 
{{sessionExpiryInterval}} greater than 0, or camel-paho with 
{{cleanSession=false}}, which is the documented way to keep a durable 
subscription. Paho 1.2.5 handles such a message on its receiver thread while 
the client may still have no callback. Checked with javap:

* {{CommsCallback.messageArrived(MqttPublish)}} (mqttv5 and mqttv3) queues the 
message only when an {{mqttCallback}} or a topic listener is set. Otherwise it 
returns: the message is not delivered and, for QoS 1, not acknowledged (the 
PUBACK is sent by {{handleMessage}} after delivery);
* mqttv5 {{ClientState.notifyReceivedMsg}} sends PUBREC for a QoS 2 PUBLISH 
right after {{callback.messageArrived}} whether or not it was delivered, and 
{{handleInboundPubRel}} sends PUBCOMP. The broker therefore considers the 
message delivered: *a QoS 2 message (the default {{qos}} of camel-paho-mqtt5) 
is lost*. A QoS 1 message stays unacknowledged until the client connects again;
* mqttv3 delivers a QoS 2 message on PUBREL and sends PUBCOMP only after 
delivery, so QoS 1 and QoS 2 messages wait until the next connect. With the 
default memory persistence they are lost when the client is created again 
(route or context restart): a PUBREL for an unknown id is answered with PUBCOMP.

The window is small (between CONNACK and {{setCallback}}), but the broker sends 
the queued messages as soon as the session resumes, so the first messages of a 
route start after downtime are the ones at risk. Claus Ibsen raised the 
ordering in the review of #28197 (CAMEL-25793).

*Fix*: set the callback first, then connect the client that the consumer 
created. A client given with the {{client}} option is connected by the user, as 
before.

*Tests*: new {{PahoMqtt5ConsumerSessionMessagesTest}} (QoS 2, 
{{cleanStart=false}}, {{sessionExpiryInterval=3600}}) and 
{{PahoConsumerSessionMessagesTest}} (QoS 1, {{cleanSession=false}}). In both, a 
mocked client delivers a message from {{connect()}} to the callback set at that 
time and drops it when there is none, like Paho 1.2.5 (comment in the test). 
Both fail on main: {{mock://result Received message count. Expected: <1> but 
was: <0>}}. camel-paho-mqtt5 unit tests with the fix: 18 run, 0 failures. 
camel-paho unit tests: 29 run, 8 errors, the same 8 on main: 
{{PahoComponentTest}} (7) and {{PahoManualAcksTest}} (1) cannot open a socket 
to the embedded Artemis broker in my sandbox ({{SocketException: Invalid 
argument}}); CI runs them.

*How it was found*: Claus Ibsen's review comment on #28197, confirmed against 
the Paho 1.2.5 jars with javap and the JUnit tests above.

*Affected*: main, camel-4.22.x, camel-4.18.x and camel-4.14.x (the same order 
in {{doStart}}; read, not run).

_Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to