updated and tested till end of lesson 4
This commit is contained in:
+56
-17
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user