Skip to content

Commit fae197a

Browse files
authored
manual puback (#680)
1 parent cd5115c commit fae197a

4 files changed

Lines changed: 78 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The primary purpose of the AWS IoT Device SDK for Python v2 is to simplify the p
2626
* Integrated service clients for AWS IoT Core services
2727
* Secure device connections to AWS IoT Core using MQTT protocol including MQTT 5.0
2828
* Support for [multiple authentication methods and connection types](./documents/MQTT5_Userguide.md#how-to-create-an-mqtt5-client-based-on-desired-connection-method)
29+
* Support for [manual publish acknowledgement](./documents/MQTT5_Userguide.md#manual-publish-acknowledgement) for control over QoS 1 PUBACK delivery
2930

3031
#### Supported AWS IoT Core services
3132

documents/FAQ.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* [What certificates do I need?](#what-certificates-do-i-need)
1212
* [Where can I find MQTT 311 Samples?](#where-can-i-find-mqtt-311-samples)
1313
* [Certificate and Private Key Usage Across Different Versions of the SDK on macOS](#certificate-and-private-key-usage-across-different-versions-of-the-sdk-on-macos)
14+
* [Manual Publish Acknowledgement and QoS 1 Redelivery](#manual-publish-acknowledgement-and-qos-1-redelivery)
1415
* [I still have more questions about this sdk?](#i-still-have-more-questions-about-this-sdk)
1516

1617
### Where should I start?
@@ -158,6 +159,18 @@ The MQTT 311 Samples can be found in the v1.24.0 samples folder [here](https://g
158159
### Certificate and Private Key Usage Across Different Versions of the SDK on macOS
159160
A certificate and private key pair cannot be shared on a macOS device between aws-iot-device-sdk-python-v2 v1.27.0 and any other versions. In the update to v1.27.0 we migrated macOS from using Apple's deprecated Security Framework to SecItem API. In doing so, certificate and private keys are imported in a non-backwards compatible manner into the Apple Keychain.
160161

162+
### Manual Publish Acknowledgement and QoS 1 Redelivery
163+
164+
When using [manual publish acknowledgement](./MQTT5_Userguide.md#manual-publish-acknowledgement), there are two important behaviors to be aware of regarding QoS 1 message redelivery:
165+
166+
**Broker redelivery of unacknowledged publishes**
167+
168+
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 the manual publish acknowledgement is not acquired again for a redelivered packet, the acknowledgement will be sent automatically.
169+
170+
**Session resumption after disconnect/reconnect**
171+
172+
Upon a disconnect and reconnect of the MQTT5 client, if a session is resumed, any previously acquired acknowledgement handle is void. The broker will resend the unacknowledged PUBLISH packet, and the acknowledgement must be reacquired from that resent packet. If the resent packet is not handled for manual acknowledgement, the acknowledgement will be sent automatically.
173+
161174
### I still have more questions about this sdk?
162175

163176
* [Here](https://docs.aws.amazon.com/iot/latest/developerguide/what-is-aws-iot.html) are the AWS IoT Core docs for more details about IoT Core

documents/MQTT5_Userguide.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* [Subscribe](#subscribe)
2424
* [Unsubscribe](#unsubscribe)
2525
* [Publish](#publish)
26+
* [Advanced Operations and Settings](#advanced-operations-and-settings)
27+
* [Manual Publish Acknowledgement](#manual-publish-acknowledgement)
2628
* [MQTT5 Best Practices](#mqtt5-best-practices)
2729

2830
## **Introduction**
@@ -340,6 +342,67 @@ The `stop()` API supports a DISCONNECT packet as an optional parameter. If supp
340342
session_expiry_interval_sec = 3600))
341343
```
342344

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+
343406
## **MQTT5 Best Practices**
344407

345408
Below are some best practices for the MQTT5 client that are recommended to follow for the best development experience:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _load_version():
4040
"Operating System :: OS Independent",
4141
],
4242
install_requires=[
43-
'awscrt==0.31.3',
43+
'awscrt==0.32.1',
4444
],
4545
python_requires='>=3.8',
4646
)

0 commit comments

Comments
 (0)