Skip to main content

Quality of service

MQTT acknowledges a delivery with one packet at QoS 1 and a four-packet handshake at QoS 2; this crate sends the acknowledgement when the handler is done.

One delivery at each quality of service: the packets the server and the service exchange, and where the handler runsMQTT serverThis serviceQoS 0: at most onceQoS 1: at least onceQoS 2: exactly oncePUBLISHThe handler runsPUBLISHThe handler runsPUBACK on ackPUBLISHThe handler runsPUBREC on ackPUBRELPUBCOMP by rumqttc
The diagram as text
  1. QoS 0: at most once: PUBLISH; The handler runs
  2. QoS 1: at least once: PUBLISH; The handler runs; PUBACK on ack
  3. QoS 2: exactly once: PUBLISH; The handler runs; PUBREC on ack; PUBREL; PUBCOMP by rumqttc
  4. MQTT server: PUBLISH; PUBLISH; PUBLISH; PUBREL
  5. This service: The handler runs; The handler runs; PUBACK on ack; The handler runs; PUBREC on ack; PUBCOMP by rumqttc
  6. PUBLISH → The handler runs
  7. PUBLISH → The handler runs
  8. The handler runs → PUBACK on ack
  9. PUBLISH → The handler runs
  10. The handler runs → PUBREC on ack
  11. PUBREC on ack → PUBREL
  12. PUBREL → PUBCOMP by rumqttc

The quality of service is chosen twice: by the publisher for its message, and by the subscription for what it accepts. A delivery travels at the lesser of the two, so a QoS 0 publish reaches a QoS 1 subscription at QoS 0. The Qos of a descriptor sets the subscription's side, and the publish policy sets the message's.

At QoS 0 the server sends the PUBLISH and forgets it. Nothing travels back, so a QoS 0 delivery has nothing to acknowledge: ack reports AckError::Unsupported, and the runtime logs it.

At QoS 1 and QoS 2 the server keeps the message until the service answers. This crate connects with manual acknowledgements, so rumqttc hands each PUBLISH to the subscription and sends nothing on its own. The acknowledgement leaves when the delivery is acknowledged, after the handler returns: PUBACK at QoS 1, PUBREC at QoS 2. The PUBREL and PUBCOMP that finish QoS 2 are exchanged by rumqttc itself.

MQTT has no negative acknowledgement. A QoS 1 or QoS 2 delivery the service never acknowledges stays with the server, which sends it again only when a persistent session resumes on a new connection, marked as a duplicate. Sessions draws that resumption, and Settlement what each outcome of a handler sends.

The client announces a Receive Maximum when it connects: how many QoS 1 and QoS 2 deliveries it takes without acknowledging them. Once that many are outstanding, the server sends no more QoS 1 or QoS 2 messages on the connection until one is acknowledged. This crate announces 1000 by default, and receive_maximum changes it. The window is the bound on what a slow subscription has waiting for it. QoS 0 deliveries take no part in it.

A publish from the service returns once rumqttc has taken the message onto its request channel, which holds 64 requests, not once the server has acknowledged it. Each QoS 1 and QoS 2 publish is kept until the server acknowledges it. After a reconnect that resumes the session, rumqttc sends them again the way the protocol says. After a reconnect that starts a new session, the connection task sends them again as new publishes. The server cannot tell a message it already received, so such a message may arrive twice, at QoS 2 too.

The flows are the protocol's own, from sections 4.3 and 4.9 of the MQTT 5.0 standard.