updated and tested till end of lesson 4

This commit is contained in:
2026-10-11 15:00:58 +03:30
parent d73090946b
commit 2d639d78eb
18 changed files with 1120 additions and 187 deletions
+56 -17
View File
@@ -1,11 +1,35 @@
# Section 2 — Understand a Go MQTT 5 connection
# 🔌 Section 2 — Understand a Go MQTT 5 connection
Prerequisite: Section 1's broker and backend credentials work. This section contains a complete small program. Type it in stages, compile after each meaningful change, and explain the code before running the failure exercises.
**Version baseline:** Paho `v0.23.0`, verified from upstream release tags on 2026-10-07. It requires Go 1.24 or newer; Go 1.25 is compatible. The matching local reference is `references/paho.golang-v0.23.0/` (commit `1aa03969c5932464359b3e4ed752d9ac61abccc9`).
## 🎬 Start with the system story
## Working directory and file placement
> 💡 **Story question:** The broker is running and has accepted CLI clients. How does the Go backend become another MQTT client, and what event proves the broker accepted its connection?
The Go process loads its connection values, gives AutoPaho a client configuration, and starts a connection manager. AutoPaho manages the connection lifecycle; the underlying Paho client performs MQTT 5 protocol exchanges. The manager can start before the network connection succeeds, so the application waits for a successful CONNACK through `AwaitConnection`.
```mermaid
sequenceDiagram
participant App as Go backend application
participant Auto as AutoPaho manager
participant Paho as Paho MQTT 5 client
participant Broker as Mosquitto broker
App->>Auto: NewConnection(lifecycle context, config)
Auto->>Paho: create and manage client connection
Paho->>Broker: TCP connection, then CONNECT
Broker->>Broker: authenticate client credentials
Broker-->>Paho: CONNACK accepted or rejected
Paho-->>Auto: connection state / callback
App->>Auto: AwaitConnection(startup deadline)
Auto-->>App: connected or startup error
```
The backend is an MQTT client, just like the device. Its application role does not make the broker handshake different. A successful CONNACK proves connection acceptance; subscriptions, device availability, and business completion are later evidence. See [Lesson 0](00-system-lifecycle.md) for the complete lifecycle.
## 📁 Working directory and file placement
Run every shell command in this lesson from the learning project root:
@@ -15,7 +39,11 @@ cd /home/ryan/Media/Code/Code/robot-market/mqtt-5-learning
Paths such as `cmd/backend/main.go` are relative to this directory. Markdown files under `lessons/` explain the work; create the application files at the paths shown, not inside `lessons/` or `references/`. Code blocks labeled Go, TOML, YAML, or conf are file contents; shell blocks are terminal commands. Create parent directories before saving files.
## 1. Build the connection program
## 🔌 1. Build the connection program
> 💡 **Story question:** Which settings and lifecycle controls must the Go process pass to the client library so a connection attempt can start and stop predictably?
The program builds one AutoPaho configuration from the broker URL, credentials, Client ID, connection options, and callbacks. The root context owns the manager lifetime; a separate startup context bounds how long the application waits for the first connection.
Create the directory first:
@@ -115,7 +143,11 @@ func run() error {
```
## 2. Understand the connection lifecycle
## 🔌 2. Understand the connection lifecycle
> 💡 **Story question:** What is happening between creating the manager and logging “connection ready,” and why are those moments not equivalent?
Trace the background attempt through transport connection, MQTT CONNECT, broker authentication, CONNACK, and `AwaitConnection`. Then trace what AutoPaho does when the connection drops.
Before reading the full program, predict what evidence you need at each stage:
@@ -149,22 +181,21 @@ There are three different contexts here. The signal context controls the program
Paho v0.23.0's `Disconnect(ctx)` cancels the manager and waits for manager shutdown with the provided deadline. Its `Done()` documentation notes that underlying MQTT cleanup may still be completing; neither API is proof that application data was persisted or device work was finished.
## 3. Run it
## ▶️ 3. Run it
In zsh, read your backend password without echoing it:
> 💡 **Story question:** Which output tells you that the broker accepted the client, and what does a clean Ctrl+C demonstrate about lifecycle ownership?
Run the process with valid lab credentials, observe the acceptance evidence, then stop it and compare graceful disconnect with a process that simply disappears.
The backend reads its username and password from `configs/lab.toml`:
```sh
export TEST_MQTT5_MQTT_USERNAME=backend
read -rs 'TEST_MQTT5_MQTT_PASSWORD?Backend lab password: '
export TEST_MQTT5_MQTT_PASSWORD
go run ./cmd/backend
```
`export NAME=value` puts a variable into this terminal's environment so child processes such as `go run` inherit it. The `read` line uses zsh syntax: `-r` preserves backslashes, `-s` hides typed characters, and `NAME?prompt` selects the variable and prompt. Enter the password you created in Lesson 1; this does not create a broker user. The second `export` exposes that newly read variable to the Go process. In bash the prompt syntax differs; do not copy this zsh-specific line unchanged.
`go run ./cmd/backend` compiles the package and runs it in the foreground. `./` means relative to the project root. Ctrl+C sends an interrupt to the foreground program; `signal.NotifyContext` turns it into context cancellation, allowing your cleanup code to run.
`go run ./cmd/backend` compiles the package and runs it in the foreground. `./` means relative to the project root. Ctrl+C sends an interrupt to the foreground program; `signal.NotifyContext` turns it into context cancellation, allowing your cleanup code to run. After the process exits, `unset TEST_MQTT5_MQTT_PASSWORD` removes the credential from this shell's environment; it does not rotate the broker credential.
Environment variables avoid password literals in this command but are not a secrets vault. Use only lab credentials. Expect `connected` and `connection ready`; callback log order can vary. Press Ctrl+C and verify exit within the shutdown deadline.
The TOML file contains the disposable local lab password. Use only lab credentials. Expect `connected` and `connection ready`; callback log order can vary. Press Ctrl+C and verify exit within the shutdown deadline.
Run syntax checks after creating the file:
@@ -178,7 +209,11 @@ go vet ./cmd/backend
`go build` emits a binary in the current directory; remove or ignore it as appropriate. A build verifies syntax/types, not connection behavior.
## 4. Observe the protocol and failures
## ⚠️ 4. Observe the protocol and failures
> 💡 **Story question:** How can you tell whether a failure happened before MQTT, during broker authentication, or after an established connection was lost?
Change one condition at a time and compare the connection callbacks, reason information, retry behavior, and shutdown outcome.
CONNECT carries your client ID, authentication fields, keepalive, and session properties. A successful CONNACK is connection evidence. Bad credentials produce an unsuccessful connection attempt; the rejected CONNACK is handled by the connection-error path rather than your success callback.
@@ -188,7 +223,7 @@ CONNECT carries your client ID, authentication fields, keepalive, and session pr
4. Run two copies using the same client ID. Observe connection takeover/reconnect behavior, then stop both. Unique IDs are necessary for concurrently running clients.
5. Press Ctrl+C while the broker is unavailable. Cancellation should interrupt the wait; do not wait for the full startup deadline.
## Cautions and troubleshooting
## 🔎 Cautions and troubleshooting
- AutoPaho handles connection management; it does not invent topic authorization, business retries, or durable command storage.
- Do not call `log.Fatal` from callbacks. It terminates the process without running deferred cleanup.
@@ -199,7 +234,11 @@ CONNECT carries your client ID, authentication fields, keepalive, and session pr
**Completion:** Explain every field in `cfg`, distinguish the three contexts, and demonstrate successful startup, failed startup, reconnect, and cancellation.
## Questions to answer before Section 3
## ✅ Result — the story so far
The backend now joins the broker as an authenticated MQTT 5 client. AutoPaho starts and manages the connection; the application waits until CONNACK confirms the broker accepted it, then keeps running and retries after a dropped connection. The backend has no subscriptions yet, so it is connected but is not listening for device messages.
## ❓ Questions to answer before Section 3
1. Why can `NewConnection` return before a usable broker connection exists?
2. What would happen if you passed `startup` to `NewConnection`?
@@ -213,7 +252,7 @@ CONNECT carries your client ID, authentication fields, keepalive, and session pr
</details>
## Sources
## 🔗 Sources
- [AutoPaho API v0.23.0](https://pkg.go.dev/github.com/eclipse/paho.golang@v0.23.0/autopaho)
- [Tagged connection manager source](https://github.com/eclipse-paho/paho.golang/blob/v0.23.0/autopaho/auto.go)