|
24 | 24 | - [Subscribe](#subscribe) |
25 | 25 | - [Unsubscribe](#unsubscribe) |
26 | 26 | - [Publish](#publish) |
| 27 | +* [Advanced Operations and Settings](#advanced-operations-and-settings) |
| 28 | + + [Manual Publish Acknowledgement](#manual-publish-acknowledgement) |
27 | 29 | * [MQTT5 Best Practices](#mqtt5-best-practices) |
28 | 30 |
|
29 | 31 | # Introduction |
@@ -757,6 +759,73 @@ If the PUBLISH was a QoS 1 publish, then the completion callback returns a PubAc |
757 | 759 | ``` |
758 | 760 |
|
759 | 761 |
|
| 762 | +## Advanced Operations and Settings |
| 763 | +
|
| 764 | +### Manual Publish Acknowledgement |
| 765 | +
|
| 766 | +By default, the MQTT5 client automatically sends a PUBACK for every QoS 1 PUBLISH it receives, immediately after the `OnPublishReceivedHandler` 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. |
| 767 | +
|
| 768 | +To take manual control of the PUBACK, call `eventData.acquirePublishAcknowledgement()` **within** the `OnPublishReceivedHandler` callback. This returns a `ScopedResource<PublishAcknowledgementHandle>` that you can store and use later to send the PUBACK by calling `client->InvokePublishAcknowledgement()`. |
| 769 | +
|
| 770 | +**Important constraints:** |
| 771 | +* `acquirePublishAcknowledgement()` must be called within the `OnPublishReceivedHandler` callback. Calling it after the callback returns or from a different thread will return `nullptr`. |
| 772 | +* `acquirePublishAcknowledgement()` may only be called once per received PUBLISH. Subsequent calls return `nullptr`. |
| 773 | +* This is only relevant for QoS 1 messages. For QoS 0 messages, `acquirePublishAcknowledgement()` returns `nullptr`. |
| 774 | +* If `acquirePublishAcknowledgement()` is not called (or returns `nullptr`), the client will automatically send the PUBACK when the callback returns. |
| 775 | +
|
| 776 | +The following example shows how to acquire the acknowledgement handle within the callback and invoke it later: |
| 777 | +
|
| 778 | +```cpp |
| 779 | + // A shared location to store the acknowledgement handle for later use |
| 780 | + Crt::ScopedResource<Mqtt5::PublishAcknowledgementHandle> pendingAck; |
| 781 | +
|
| 782 | + // Set the publish received callback on the builder |
| 783 | + builder->WithPublishReceivedCallback( |
| 784 | + [&pendingAck](const Mqtt5::PublishReceivedEventData &eventData) { |
| 785 | + if (eventData.publishPacket == nullptr) |
| 786 | + return; |
| 787 | +
|
| 788 | + fprintf(stdout, "Publish received on topic %s\n", |
| 789 | + eventData.publishPacket->getTopic().c_str()); |
| 790 | +
|
| 791 | + // Acquire manual control of the PUBACK for this QoS 1 message. |
| 792 | + // This must be called within the callback. After the callback returns, |
| 793 | + // acquirePublishAcknowledgement() will return nullptr. |
| 794 | + pendingAck = eventData.acquirePublishAcknowledgement(); |
| 795 | +
|
| 796 | + if (pendingAck == nullptr) |
| 797 | + { |
| 798 | + // QoS 0 message or acknowledgement already taken — nothing to do. |
| 799 | + return; |
| 800 | + } |
| 801 | +
|
| 802 | + // The PUBACK will NOT be sent automatically because we acquired the handle. |
| 803 | + }); |
| 804 | +
|
| 805 | + std::shared_ptr<Aws::Crt::Mqtt5Client> client = builder->Build(); |
| 806 | +
|
| 807 | + // ... connect, subscribe, and receive messages ... |
| 808 | +
|
| 809 | + // After processing is complete, send the PUBACK by invoking the acknowledgement. |
| 810 | + if (pendingAck != nullptr) |
| 811 | + { |
| 812 | + if (!client->InvokePublishAcknowledgement(*pendingAck)) |
| 813 | + { |
| 814 | + fprintf(stdout, "Failed to invoke publish acknowledgement.\n"); |
| 815 | + } |
| 816 | + } |
| 817 | +
|
| 818 | +``` |
| 819 | + |
| 820 | +**AWS IoT broker redelivery behavior** |
| 821 | + |
| 822 | +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 `acquirePublishAcknowledgement()` is not called again for a redelivered packet, the acknowledgement will be sent automatically. |
| 823 | + |
| 824 | +**Session resumption after disconnect/reconnect** |
| 825 | + |
| 826 | +Upon a disconnect and reconnect of the MQTT5 client, if a session is resumed, any previously acquired `ScopedResource<PublishAcknowledgementHandle>` is void. The broker will resend the unacknowledged PUBLISH packet, and `acquirePublishAcknowledgement()` 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. |
| 827 | + |
| 828 | + |
760 | 829 | # MQTT5 Best Practices |
761 | 830 |
|
762 | 831 | Below are some best practices for the MQTT5 client that are recommended to follow for the best development experience: |
|
0 commit comments