|
24 | 24 | + [Publish](#publish) |
25 | 25 | + [Subscribe and Unsubscribe](#subscribe-and-unsubscribe) |
26 | 26 | + [MQTT5 Best Practices](#mqtt5-best-practices) |
| 27 | +* [Advanced Operations and Settings](#advanced-operations-and-settings) |
| 28 | + + [Manual Publish Acknowledgement](#manual-publish-acknowledgement) |
27 | 29 |
|
28 | 30 | # Introduction |
29 | 31 |
|
@@ -564,3 +566,54 @@ Below are some best practices for the MQTT5 client that are recommended to follo |
564 | 566 | * Make sure to always call `close()` when finished a MQTT5 client to avoid native resource leaks! |
565 | 567 | * For [publish](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/Mqtt5Client.html#publish(software.amazon.awssdk.crt.mqtt5.packets.PublishPacket)), [subscribe](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/Mqtt5Client.html#subscribe(software.amazon.awssdk.crt.mqtt5.packets.SubscribePacket)), and [unsubscribe](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/Mqtt5Client.html#unsubscribe(software.amazon.awssdk.crt.mqtt5.packets.UnsubscribePacket)), make sure to check the reason codes in the ACK ([PubAckPacket](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/packets/PubAckPacket.html), [SubAckPacket](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/packets/SubAckPacket.html), and [UnsubAckPacket](https://awslabs.github.io/aws-crt-java/software/amazon/awssdk/crt/mqtt5/packets/UnsubAckPacket.html) respectively) to see if the operation actually succeeded. |
566 | 568 | * You MUST NOT perform blocking operations on any callback, or you will cause a deadlock. For example: in the `onMessageReceived` callback, do not send a publish, and then wait for the future to complete within the callback. The Client cannot do work until your callback returns, so the thread will be stuck. |
| 569 | +
|
| 570 | +## Advanced Operations and Settings |
| 571 | +
|
| 572 | +### Manual Publish Acknowledgement |
| 573 | +
|
| 574 | +By default, the MQTT5 client automatically sends a PUBACK for every QoS 1 PUBLISH it receives, immediately after the `onMessageReceived` 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. |
| 575 | +
|
| 576 | +To take manual control of the PUBACK, call `publishReturn.acquirePublishAcknowledgementControl()` **within** the `onMessageReceived` callback. This returns a `Mqtt5PublishAcknowledgementControlHandle` that you can store and use later to send the PUBACK by calling `client.invokePublishAcknowledgement()`. |
| 577 | +
|
| 578 | +**Important constraints:** |
| 579 | +* `acquirePublishAcknowledgementControl()` must be called within the `onMessageReceived` callback. Calling it outside the callback or after it returns will return `null`. |
| 580 | +* `acquirePublishAcknowledgementControl()` may only be called once per received PUBLISH. Subsequent calls will return `null`. |
| 581 | +* This is only relevant for QoS 1 messages. Calling it on a QoS 0 message will return `null`. |
| 582 | +* If `acquirePublishAcknowledgementControl()` is not called, the client will automatically send the PUBACK when the callback returns. |
| 583 | +
|
| 584 | +The following example shows how to acquire the acknowledgement handle within the callback and invoke it later: |
| 585 | +
|
| 586 | +~~~ java |
| 587 | +// A shared location to store the acknowledgement handle for later use |
| 588 | +final AtomicReference<Mqtt5PublishAcknowledgementControlHandle> pendingAck = new AtomicReference<>(); |
| 589 | +
|
| 590 | +class MyPublishEvents implements Mqtt5ClientOptions.PublishEvents { |
| 591 | + @Override |
| 592 | + public void onMessageReceived(Mqtt5Client client, PublishReturn publishReturn) { |
| 593 | + System.out.println("Message received on topic: " + |
| 594 | + publishReturn.getPublishPacket().getTopic()); |
| 595 | +
|
| 596 | + if (publishReturn.getPublishPacket().getQOS() == QOS.AT_LEAST_ONCE) { |
| 597 | + // Acquire manual control of the PUBACK for this QoS 1 message. |
| 598 | + // This must be called within the callback. Calling it outside the callback |
| 599 | + // or after it returns will return null. |
| 600 | + Mqtt5PublishAcknowledgementControlHandle handle = |
| 601 | + publishReturn.acquirePublishAcknowledgementControl(); |
| 602 | +
|
| 603 | + if (handle != null) { |
| 604 | + // The PUBACK will NOT be sent automatically because we acquired the handle. |
| 605 | + // Store it for later use after processing is complete. |
| 606 | + pendingAck.set(handle); |
| 607 | + } |
| 608 | + } |
| 609 | + } |
| 610 | +} |
| 611 | +
|
| 612 | +// ... build client, connect, and subscribe ... |
| 613 | +
|
| 614 | +// After processing is complete, send the PUBACK by invoking the acknowledgement. |
| 615 | +Mqtt5PublishAcknowledgementControlHandle handle = pendingAck.getAndSet(null); |
| 616 | +if (handle != null) { |
| 617 | + client.invokePublishAcknowledgement(handle); |
| 618 | +} |
| 619 | +~~~ |
0 commit comments