Settlement
What ack, drop, retry and retry_after become on
MQTT: one acknowledgement at QoS 1 and 2, nothing at QoS 0, and copies the runtime publishes.
The diagram as text
- Handler: ack(); drop(); retry(); retry() under a cap; retry_after(d); no outcome: a batch let go
- Sent: PUBACK PUBREC; PUBACK PUBREC; nothing; PUBACK PUBREC; PUBACK PUBREC; nothing; At QoS 0 nothing is sent: ack and drop report AckError::Unsupported, and a copy the runtime publishes still goes out
- Then: finished; finished, the message is let go; back when a persistent session resumes; a copy published now; a copy published after d; as retry(): back on resume
- ack() → PUBACK PUBREC
- PUBACK PUBREC → finished
- drop() → PUBACK PUBREC
- PUBACK PUBREC → finished, the message is let go
- retry() → nothing
- nothing → back when a persistent session resumes
- retry() under a cap → PUBACK PUBREC
- PUBACK PUBREC → a copy published now
- retry_after(d) → PUBACK PUBREC
- PUBACK PUBREC → a copy published after d
- no outcome: a batch let go → nothing
- nothing → as retry(): back on resume
MQTT has one answer to a delivery, the acknowledgement: PUBACK at QoS 1, PUBREC at QoS 2. ack
sends it. drop sends it too, because acknowledging is the only way the protocol lets a service
end a message.
MQTT has no negative acknowledgement, so the server never sends a message again on the live
connection. A retry() with nothing declared reports
AckError::Unsupported, which the runtime logs, and leaves the delivery unacknowledged. The server
sends it again only when a persistent session resumes on a new connection. Until then it holds one
slot of the Receive Maximum window: once the window is full of such deliveries, the
server sends no more QoS 1 or QoS 2 messages on the connection. A batch the handler lets go stays
unacknowledged the same way.
A retry within the session is a copy the runtime publishes. retry_after(d) acknowledges the
original, waits for d and publishes a copy. A retry() under a declared cap or dead-letter
topic publishes its copy at once. A QoS 0 delivery has nothing to acknowledge, and its copy goes
out all the same.
| Outcome | QoS 0 |
|---|---|
ack, drop | AckError::Unsupported |
retry() | AckError::Unsupported; under a declared cap, a copy published at once |
retry_after(d) | a copy published after d |
| no outcome | nothing |
Retries
The diagram as text
- Below the cap: The original is acknowledged, the copy waits d; MqttTopic: the copy goes to its topic; MqttFilter: to the topic the mount site or a transform names
- At the cap: Dead-letter topic: the delivery published there; No dead letter: acknowledged and let go
- A delivery its attempt read from x-ruststream-retry-count → The handler returns retry_after(d), or retry() under a declaration: handled
- The handler returns retry_after(d), or retry() under a declaration → max_attempts: is this attempt below the cap?: a retry
- max_attempts: is this attempt below the cap? → Below the cap: below
- max_attempts: is this attempt below the cap? → At the cap: at the cap
- A copy is a publish: every subscription whose filter matches its topic receives it. A copy waiting for its delay lives in the process, and a crash before the timer fires loses it.
The cap is declared at the mount site with
max_attempts, and the first delivery counts
as one. MQTT counts no deliveries of its own, so the runtime counts the copies it publishes, in
each copy's x-ruststream-retry-count header.
Below the cap, the copy goes to the address of the subscription's form. An
MqttTopic addresses its own topic, a shared one
included, so its registration names nothing. An
MqttFilter matches many topics and publishes to
none, so its registration names the topic a copy goes to,
once or per delivery through a transform. A filter registration that names neither does not start.
At the cap, the delivery goes to the dead-letter topic, payload unchanged. With no dead-letter topic declared, it is acknowledged and let go.
A copy is an ordinary publish, so it reaches every subscription whose filter matches its topic, in this service and in others. A dead-letter topic that a live filter matches hands the message straight back, so it takes a name no subscription reads. A copy waiting for its delay lives in the process: a graceful shutdown waits for it, and a crash before the timer fires loses it.