|
| 1 | +# Request / Response |
| 2 | + |
| 3 | +MQTT 5.0 defines a first-class request/response pattern via two |
| 4 | +`PUBLISH` properties: `response_topic` and `correlation_data`. zmqtt |
| 5 | +implements this as a single `await client.request(…)` call. |
| 6 | + |
| 7 | +## Basic usage |
| 8 | + |
| 9 | +```python |
| 10 | +from zmqtt import create_client |
| 11 | + |
| 12 | +async with create_client("broker", version="5.0") as client: |
| 13 | + reply = await client.request("services/calculator", b"2+2") |
| 14 | + print(reply.payload) |
| 15 | +``` |
| 16 | + |
| 17 | +`request()` handles the full flow automatically: |
| 18 | + |
| 19 | +1. Subscribes to a unique reply topic before publishing. |
| 20 | +2. Publishes the request with `response_topic` and `correlation_data` set. |
| 21 | +3. Waits for the first message on the reply topic and returns it. |
| 22 | +4. Unsubscribes on return, timeout, or cancellation. |
| 23 | + |
| 24 | +## Customising via `PublishProperties` |
| 25 | + |
| 26 | +Pass a `PublishProperties` instance to control any field of the outgoing |
| 27 | +PUBLISH. Two fields receive special treatment: |
| 28 | + |
| 29 | +| Field | Behaviour | |
| 30 | +| ------------------ | -------------------------------------------------------------------------------------- | |
| 31 | +| `response_topic` | Used as the reply topic instead of the auto-generated one. Must not contain wildcards. | |
| 32 | +| `correlation_data` | Forwarded to the responder as-is. Auto-generated (16 random bytes) when absent. | |
| 33 | + |
| 34 | +All other fields (`content_type`, `message_expiry_interval`, |
| 35 | +`user_properties`, …) are forwarded unchanged. |
| 36 | + |
| 37 | +```python |
| 38 | +from zmqtt import PublishProperties |
| 39 | + |
| 40 | +reply = await client.request( |
| 41 | + "services/translate", |
| 42 | + b"hello", |
| 43 | + properties=PublishProperties( |
| 44 | + content_type="text/plain", |
| 45 | + response_topic="my-app/replies/translate", |
| 46 | + correlation_data=b"req-001", |
| 47 | + ), |
| 48 | + timeout=10.0, |
| 49 | +) |
| 50 | +``` |
| 51 | + |
| 52 | +## Implementing a responder |
| 53 | + |
| 54 | +The responder reads `response_topic` and `correlation_data` from the |
| 55 | +incoming message and publishes the reply there: |
| 56 | + |
| 57 | +```python |
| 58 | +async with client.subscribe("services/translate") as sub: |
| 59 | + async for msg in sub: |
| 60 | + assert msg.properties is not None |
| 61 | + result = translate(msg.payload) |
| 62 | + await client.publish( |
| 63 | + msg.properties.response_topic, |
| 64 | + result, |
| 65 | + properties=PublishProperties( |
| 66 | + correlation_data=msg.properties.correlation_data, |
| 67 | + ), |
| 68 | + ) |
| 69 | +``` |
| 70 | + |
| 71 | +## Timeout |
| 72 | + |
| 73 | +`request()` raises `asyncio.TimeoutError` when no reply arrives within |
| 74 | +`timeout` seconds (default `30.0`). The reply subscription is always |
| 75 | +cleaned up, even on timeout or cancellation. |
| 76 | + |
| 77 | +```python |
| 78 | +import asyncio |
| 79 | + |
| 80 | +try: |
| 81 | + reply = await client.request("slow/service", b"ping", timeout=5.0) |
| 82 | +except asyncio.TimeoutError: |
| 83 | + print("Service did not respond in time") |
| 84 | +``` |
| 85 | + |
| 86 | +## Errors |
| 87 | + |
| 88 | +| Exception | Raised when | |
| 89 | +| ----------------------- | ------------------------------------------------- | |
| 90 | +| `RuntimeError` | `request()` is called on an MQTT 3.1.1 connection | |
| 91 | +| `MQTTInvalidTopicError` | `properties.response_topic` contains wildcards | |
| 92 | +| `MQTTDisconnectedError` | Connection is lost while waiting for the reply | |
| 93 | +| `asyncio.TimeoutError` | No reply arrives within `timeout` seconds | |
| 94 | + |
| 95 | +!!! note |
| 96 | +`request()` is only available on MQTT 5.0 connections. Use |
| 97 | +`create_client(…, version="5.0")` or `MQTTClient(…, version="5.0")`. |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +**See also:** [MQTT 5.0](mqtt5.md) · [Publishing](../publishing.md) · [Error Handling](../error-handling.md) |
0 commit comments