feat: expand MQTT contract and reliability lessons

This commit is contained in:
2026-10-13 18:08:17 +03:30
parent 2d639d78eb
commit f9ab91ed60
17 changed files with 2083 additions and 91 deletions
+13 -1
View File
@@ -4,6 +4,10 @@ Prerequisite: complete the session experiments in Lesson 9. Continue the same la
## 1. Give every timer one responsibility
**❓ Question:** **A ping is queued while a device is offline, then reaches it after the operator has changed the desired setting. Which timer can stop stale delivery, and which check must still run on the device?**
**💬 Answer:** MQTT Message Expiry limits how long the broker may forward the publication. The device must also check the application's absolute deadline before starting the action, because work may have spent time in a local queue or arrived just before expiry. Neither timer can reverse an action already started.
| Timer | What expires | What it cannot prove |
| --- | --- | --- |
| Go publish context | Your wait for the publication operation | That the device never received it |
@@ -13,7 +17,7 @@ Prerequisite: complete the session experiments in Lesson 9. Continue the same la
| Keep Alive | Acceptable MQTT connection inactivity | That the application is healthy |
| Will Delay | Delay before an eligible Will is published | That the device is physically broken |
A vending configuration command that was useful five minutes ago may be wrong now. Use Message Expiry to limit stale delivery and an application deadline to reject stale execution after delivery. A response timeout merely tells the caller it lacks a result.
A vending configuration command that was useful five minutes ago may be wrong now. Use Message Expiry to limit stale delivery and an application deadline to reject stale execution after delivery. A response timeout merely tells the caller it lacks a result. A PUBACK can arrive before the simulator validates the command; if the application rejects it, that MQTT acknowledgement remains valid for the protocol step it acknowledged.
This fragment builds MQTT metadata for a five-second publication lifetime:
@@ -31,6 +35,10 @@ Attach `properties` to the outbound PUBLISH. A nil MessageExpiry omits the prope
## 2. Retained state is a latest value, not an event history
**❓ Question:** **A new simulator subscribes and receives a retained `dispense` command from last week. What design choice caused this replay?**
**💬 Answer:** A one-shot action was published with RETAIN set. Retained publications are stored by topic for future subscribers, so use retained messages for replaceable state such as desired configuration and nonretained messages for one-time actions.
A retained publication replaces the stored value for one exact topic. It can initialize a newly created subscription even when that client has never connected before. Offline session queues instead belong to an existing session and its subscriptions. Unsubscribing or deleting a session does not delete a retained value.
Use a desired-configuration topic for state such as revision 7 and a temperature setting. Use nonretained command topics for one-shot actions. A retained "dispense" would risk replay when someone subscribes later.
@@ -51,6 +59,10 @@ mosquitto_pub -h 127.0.0.1 -p 18883 -V mqttv5 -u simulator -P '<simulator-lab-pa
## 3. Model presence as evidence
**❓ Question:** **The broker's retained presence says `online`, but the last heartbeat is old. What can the backend safely conclude?**
**💬 Answer:** It can conclude only that the broker currently stores an online assertion. It cannot conclude the device is healthy now. Track backend receipt time and heartbeat freshness, and compare a connection or boot identity so delayed state does not replace newer evidence.
The simulator supplies its Will during CONNECT. The broker later publishes it when the connection ends in a way that requires a Will; it is not code that the dead simulator executes. First add simulator write/backend read ACLs for its `.../presence` topic and teach the topic parser about it.
Add these fields to the simulator's AutoPaho configuration, alongside its existing settings: