0

I would like to have a better understanding of the behavior of this library. Specifically: let's say I have an open connection (over WSS, if this change anything) with an MQTT server. I publish a message with QoS=1. My understanding is that mqtt awaits for a PUBACK message. After the ack has been received, the done callback is called and the flow is ended. What is not clear to me is the low-level stuff: how much "time" do the library awaits for the ack? what happen if the ack doesn't come? the message is resent? the connection is closed/reopened? something else? Is this behavior tunable?

Vito De Tullio
  • 2,332
  • 3
  • 33
  • 52

1 Answers1

2

Prior to answering your specific question I feel its worth outlining what the protocol requires (I'll highlight the key term). The MQTT 3.1.11 spec says:

When a Client reconnects with CleanSession set to 0, both the Client and Server MUST re-send any unacknowledged PUBLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet Identifiers [MQTT-4.4.0-1]. This is the only circumstance where a Client or Server is REQUIRED to redeliver messages.

The v5 spec tightens this:

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].

So the only time the spec requires that the publish be resent is when the client reconnects. v3.1.1 does not prohibit resending at other times but I would not recommend doing this (see this answer for more info).

Looking specifically at mqtt.js I have scanned through the code and the only resend mechanism I can see is when the connection is established (backed up by this issue). So to answer your specific questions:

how much "time" do the library awaits for the ack?

There is no limit; the callback is stored and called when the flow completes (for example).

what happen if the ack doesn't come? the message is resent? the connection is closed/reopened? something else?

Nothing. However in reality the use of TCP/IP means that if a message is not delivered then the connection should drop (and if the broker receives the message, but is unable to process it, then it should really drop the connection).

Is this behavior tunable?

I guess you could implement a timed resend but this is unlikely to be a good idea (and doing so would breach the v5 spec). A better approach might be to drop the connection if a message is not acknowledged within a set time frame. However there really should be no need to do this.

Brits
  • 14,829
  • 2
  • 18
  • 31
  • Looking at the code I agree that "nothing" is what happen "just after" the missing PUBACK. Now I have another doubt, however: as you said "the connection should drop", but how? should/could the library "force" the drop of the connection? I ask this because I just used a very dumb MITMproxy script between my client and my server, blocking the server PUBACK responses, and... nothing happened from my client for solid 10 minutes... – Vito De Tullio Jun 05 '22 at 06:31
  • "A stream of data sent on a TCP connection is delivered reliably and in order at the destination." ([RFP793](https://datatracker.ietf.org/doc/html/rfc793)). As TCP is used to transmit MQTT packets you can safely assume that either the packets will be received in order or subsequent packets will not be received at all. A [half-open](https://en.wikipedia.org/wiki/TCP_half-open) connection may prevent delivery but keepalives should detect that. The spec states that the network must "provide ordered, lossless, bi-directional connections" (so if yours does not then another protocol may be needed). – Brits Jun 05 '22 at 19:41