|
23 | 23 | * [Subscribe](#subscribe) |
24 | 24 | * [Unsubscribe](#unsubscribe) |
25 | 25 | * [Publish](#publish) |
| 26 | + * [Advanced Operations and Settings](#advanced-operations-and-settings) |
| 27 | + * [Manual Publish Acknowledgement](#manual-publish-acknowledgement) |
26 | 28 | * [MQTT5 Best Practices](#mqtt5-best-practices) |
27 | 29 |
|
28 | 30 | ## **Introduction** |
@@ -340,6 +342,67 @@ The `stop()` API supports a DISCONNECT packet as an optional parameter. If supp |
340 | 342 | session_expiry_interval_sec = 3600)) |
341 | 343 | ``` |
342 | 344 |
|
| 345 | +## Advanced Operations and Settings |
| 346 | + |
| 347 | +### Manual Publish Acknowledgement |
| 348 | + |
| 349 | +By default, the MQTT5 client automatically sends a PUBACK for every QoS 1 PUBLISH it receives, immediately after the `on_publish_callback_fn` callback returns. Manual publish acknowledgement gives you control over when that PUBACK is sent, allowing you to defer acknowledgement until after your application has fully processed the message — for example, after persisting it to a database or forwarding it to another service. |
| 350 | + |
| 351 | +To take manual control of the PUBACK, call `publish_data.acquire_publish_acknowledgement_control()` **within** the `on_publish_callback_fn` callback. This returns a `PublishAcknowledgementControlHandle` that you can store and use later to send the PUBACK by calling `client.invoke_publish_acknowledgement()`. |
| 352 | + |
| 353 | +**Important constraints:** |
| 354 | +* `acquire_publish_acknowledgement_control()` must be called within the `on_publish_callback_fn` callback. Calling it after the callback returns or from a different thread will raise a `RuntimeError`. |
| 355 | +* `acquire_publish_acknowledgement_control()` may only be called once per received PUBLISH. Subsequent calls will raise a `RuntimeError`. |
| 356 | +* This is only relevant for QoS 1 messages. For QoS 0 messages, `acquire_publish_acknowledgement_control` will be `None`. |
| 357 | +* If `acquire_publish_acknowledgement_control()` is not called, the client will automatically send the PUBACK when the callback returns. |
| 358 | + |
| 359 | +The following example shows how to acquire the acknowledgement handle within the callback and invoke it later: |
| 360 | + |
| 361 | +```python |
| 362 | +import awscrt.mqtt5 as mqtt5 |
| 363 | + |
| 364 | +# A variable to hold the acknowledgement handle for later use |
| 365 | +pending_ack = None |
| 366 | + |
| 367 | +def on_publish_received(publish_data: mqtt5.PublishReceivedData): |
| 368 | + global pending_ack |
| 369 | + |
| 370 | + print(f"Message received on topic: {publish_data.publish_packet.topic}") |
| 371 | + |
| 372 | + if publish_data.publish_packet.qos == mqtt5.QoS.AT_LEAST_ONCE: |
| 373 | + # Acquire manual control of the PUBACK for this QoS 1 message. |
| 374 | + # This must be called within the callback. After the callback returns, |
| 375 | + # acquire_publish_acknowledgement_control() will raise a RuntimeError. |
| 376 | + if publish_data.acquire_publish_acknowledgement_control is not None: |
| 377 | + pending_ack = publish_data.acquire_publish_acknowledgement_control() |
| 378 | + |
| 379 | + # The PUBACK will NOT be sent automatically because we acquired the handle. |
| 380 | + # Process the message here (e.g., persist to storage, forward to another service). |
| 381 | + |
| 382 | +# Pass the callback when creating the client |
| 383 | +client_options = mqtt5.ClientOptions( |
| 384 | + host_name = "<endpoint to connect to>", |
| 385 | + port = <port to use>, |
| 386 | + on_publish_callback_fn = on_publish_received) |
| 387 | + |
| 388 | +client = mqtt5.Client(client_options) |
| 389 | + |
| 390 | +# ... connect and subscribe ... |
| 391 | + |
| 392 | +# After processing is complete, send the PUBACK by invoking the acknowledgement. |
| 393 | +if pending_ack is not None: |
| 394 | + client.invoke_publish_acknowledgement(pending_ack) |
| 395 | + pending_ack = None |
| 396 | +``` |
| 397 | + |
| 398 | +**AWS IoT broker redelivery behavior** |
| 399 | + |
| 400 | +The AWS IoT broker will periodically resend unacknowledged QoS 1 PUBLISH packets. These redeliveries should be treated as duplicates even if the DUP flag in the PUBLISH packet is not set. If `acquire_publish_acknowledgement_control()` is not called again for a redelivered packet, the acknowledgement will be sent automatically. |
| 401 | + |
| 402 | +**Session resumption after disconnect/reconnect** |
| 403 | + |
| 404 | +Upon a disconnect and reconnect of the MQTT5 client, if a session is resumed, any previously acquired `PublishAcknowledgementControlHandle` is void. The broker will resend the unacknowledged PUBLISH packet, and `acquire_publish_acknowledgement_control()` must be called again within the callback for that resent packet. If the resent packet is not handled for manual acknowledgement, the acknowledgement will be sent automatically. |
| 405 | + |
343 | 406 | ## **MQTT5 Best Practices** |
344 | 407 |
|
345 | 408 | Below are some best practices for the MQTT5 client that are recommended to follow for the best development experience: |
|
0 commit comments