fusesource / mqtt-client

A Java MQTT Client
http://mqtt-client.fusesource.org/
Apache License 2.0
1.27k stars 368 forks source link

MQTT message duplicated after automatic reconnection #120

Open freyssin opened 4 years ago

freyssin commented 4 years ago

We have written a simple test that publishes QoS2 messages on a topic with a durable session (cleanSession= false). This test uses the FuseSource client through the callback API, with automatic reconnection feature. This test works correctly in the absence of failure, but we sometimes detect duplicated messages when network deconnections occur.

In the table below we reproduce the sequence of messages before and after the network failure (If necessary we have a wireshark capture of this sequence). As explained below it seems that the problem comes from the takeover of the client.

Client (frames sent) Server (frames sent)
PUBLISH #44  
  PUBREC #44
PUBREL #44  
===== Network failure ===== ===== Network failure =====
CONNECT  
  CONNACK
PUBLISH #44  
SUBSCRIBE #3  
  PUBREC #44
PUBREL #44  
  PUBCOMP #44
  SUBACK #3

When a failure is detected, the protocol flow should normally retry from the last unacknowledged protocol message (either PUBLISH or PUBREL). The MQTT 3.1.1 specification in section 4.3.3 states that: "In the QoS 2 delivery protocol, the Sender MUST NOT re-send the PUBLISH once it has sent the corresponding PUBREL packet.". We believe we are exactly in that case.

In the case above it seems that the client sends the PUBLISH #44 again while it has obviously received the corresponding PUBREC and sent the PUBREL.

When the server receives the PUBREL, it releases all persistency related to the message #44. So when it receives the PUBLISH #44 message again, it interprets the message as new. This results in the duplication of the message to the different subscribers.