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

Client disconnects when message is resent during the same connection #557

Closed HansHabraken closed 4 months ago

HansHabraken commented 1 year ago

Hi

I have a question regarding the behaviour of this library when manual acknowledgment is enabled. I have enabled manual acknowledgement and when a message is not acknowledged, and resent from the broker to the client, the client disconnect. I traced this behaviour back to following code block: https://github.com/hivemq/hivemq-mqtt-client/blob/v1.3.0/src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttIncomingQosHandler.java#L137

Can you elaborate on why the client behaves this way? Why is this needed?

We use the manual acknowledgement to achieve zero message loss and only send a PUBACK back to the broker when the downstream service confirms that it has received the message.

Thanks in advance!

Kind Regards Hans

sauroter commented 1 year ago

Hi @HansHabraken,

this behavior stems directly from the MQTT specification. As stated in section 4.4 Message delivery retry:

When a Client reconnects with Clean Start set to 0 and a session is present, both the Client and Server MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL packets using their original Packet Identifiers. This is the only circumstance where a Client or Server is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at any other time [MQTT-4.4.0-1].

The relevant part of the specification has been highlighted for your convenience. If the broker resends a message without a disconnection event happening between, it is violating the specification. The client treats these violations by disconnecting and printing a log statement.

Could you explain why you think a resend is necessary in this case? If the subscribing client did not crash (and disconnect), there should be no possibility of message loss.

Cheers Georg

pglombardo commented 1 year ago

Hi @HansHabraken - have you seen the previous reply? Let us know if this is still an issue for you, we'd be happy to help out.

laohuyuhai commented 12 months ago

@sauroter @pglombardo I think @HansHabraken might want features like Kafka, if the application receive one message but an error occurs during processing, he want the broker can resend the message and the client re-receive the message.

pglombardo commented 4 months ago

Hi @laohuyuhai - that's understandable and I can see the use case. But in terms of MQTT, if you enabled manual acknowledgement and then don't acknowledge the message, that message won't be resent until the that client (or another) reconnects to the broker.

I can definitely see where in certain architectures this would cause some complexity.

I'll forward this issue/scenario to the team here who contribute to the MQTT specification.

Since we have an answer and this issue has gone stale, I'll close out this issue but if anything remains, feel free to reopen or file another issue.