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
+24
View File
@@ -4,6 +4,10 @@ Study this after Sections 12–15 in [COURSE.md](../COURSE.md), or read it earli
## 1. Subscription options change what arrives
**❓ Question:** **A device publishes a retained status update and then subscribes to that same topic. Which option controls retained replay, and which option controls the RETAIN bit on forwarded live traffic?**
**💬 Answer:** Retain Handling controls retained replay at subscription time. Retain As Published controls whether the broker preserves the incoming RETAIN bit when forwarding a live publication. Neither option changes the broker's ACL decision or filters payload identity.
These fields belong to each `paho.SubscribeOptions` entry, not to the PUBLISH payload:
| Field | Meaning | Experiment |
@@ -20,6 +24,10 @@ An UNSUBSCRIBE removes a broker subscription after its UNSUBACK exchange; it doe
## 2. Shared subscriptions distribute work
**❓ Question:** **Two ingestion processes share a subscription group, and a response reaches the process that did not create the pending waiter. What fails?**
**💬 Answer:** The receiving process may have no matching in-memory command record. A shared subscription distributes each matching delivery to a group member; it does not share process memory or guarantee device affinity. Keep response correlation state shared or route responses to a common durable store.
Ordinary subscriptions on two clients each receive a matching publication. With `$share/ingest/lab/v1/devices/+/telemetry`, both clients join the `ingest` group for that filter and the broker selects a group member for a matching delivery. Give each process a unique Client ID; sharing a group is different from sharing a Client ID.
Create two authorized lab consumers, check their SUBACK results, then publish numbered synthetic telemetry. Record which instance handles each ID. Stop one consumer and repeat. Use a fresh lab group/session for the experiment so old offline state does not obscure the result. Verify the broker's shared-subscription support and effective ACL behavior before drawing conclusions.
@@ -28,6 +36,10 @@ Distribution is not guaranteed round-robin, per-device affinity, or business exa
## 3. Distinguish wire limits from application limits
**❓ Question:** **The backend sets Receive Maximum to four. Does that cap the number of telemetry jobs waiting in its Go worker queue at four?**
**💬 Answer:** No. This CONNECT limit constrains the broker's concurrent QoS 1/2 publications awaiting protocol acknowledgement on the broker-to-client direction. If callbacks acknowledge quickly after queueing, the application queue can continue to grow until its own bound is reached.
The CONNECT properties describe what this client can receive. The CONNACK properties describe what the server can receive or supports. Direction matters: changing the client's Receive Maximum constrains broker-to-client QoS 1/2 inflight publications, not the backend's outgoing command rate.
Add this field to your existing `autopaho.ClientConfig`; it is a fragment, with `net/url` and Paho imports supplied by that file:
@@ -55,6 +67,10 @@ For packet-size testing, use harmless payloads below and above a deliberately sm
## 4. Properties carry context, not trust
**❓ Question:** **A simulator sets User Property `producer=device-001`. Has the broker authenticated that device identity?**
**💬 Answer:** No. User Properties are forwarded metadata. The broker authenticates the MQTT client and applies its topic ACL; the application validates the topic, payload, and any metadata it chooses to use. Never treat a property or payload ID as proof of the publisher.
User Properties are UTF-8 key/value pairs and may repeat a key. Use them for synthetic trace context or schema hints, with size/count limits. They are not authenticated claims by themselves and are not HTTP headers that the broker interprets for your application.
```go
@@ -72,6 +88,10 @@ Subscription Identifiers let a subscriber label a subscription and identify whic
## 5. Topic aliases optimize one connection
**❓ Question:** **The broker restarted and the MQTT session resumed. Can the client safely publish using an alias-only packet from before the restart?**
**💬 Answer:** No. Topic Alias mappings belong to one network connection and direction. Reestablish the mapping after reconnect; session resumption does not restore it.
An alias associates a small integer with a topic name for one direction of one connection. The sender first establishes the mapping with the topic and alias; subsequent publications may use the alias to avoid resending the long topic string. This reduces bytes, not permission checks or payload size.
The receiver advertises its Topic Alias Maximum. Zero or absent support must not be treated as permission to send arbitrary aliases. A reconnect loses the mapping even when an MQTT session resumes. Never send an alias-only first publication after reconnect.
@@ -80,6 +100,10 @@ Read the pinned `paho/extensions/topicaliases/` implementation and its tests, pl
## 6. Read failures as protocol evidence
**❓ Question:** **A QoS 1 PUBACK has reason code `0x10` (No matching subscribers). Did the device accept the command?**
**💬 Answer:** No. The reason describes the broker's handling of that publication hop. It is not an application response from the device. The command service must wait for and validate a correlated device response, and must preserve an unknown outcome if none arrives.
Reason codes belong to a packet context. A SUBACK contains a result for each filter. A QoS 1 PUBACK describes the immediate publication hop. A DISCONNECT may describe why the broker ended a connection. None is a device business status.
| Observation | Interpretation | Next action |