Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

publish userProperties aren't returned in the PUBACK? #499

Closed
dhyeyyyy opened this issue May 22, 2024 · 5 comments
Closed

publish userProperties aren't returned in the PUBACK? #499

dhyeyyyy opened this issue May 22, 2024 · 5 comments
Labels
documentation This is a problem with documentation. needs-triage This issue or PR still needs to be triaged.

Comments

@dhyeyyyy
Copy link

Describe the issue

Looking to create a file-persistent queue for MQTT, was hoping to use userProperties to be able to link a publish with a pub ack. However- trying to experiment with this dummy program, the response contains an empty userProperties field. Is this the expected behaviour? How else could I go about connecting PUBACK's with their respective publishes?

const { iot, mqtt5, io } = require("aws-iot-device-sdk-v2");
io.enable_logging(io.LogLevel.DEBUG);

const certPath = "/home/dhyey/certificates";
const builder =
  iot.AwsIotMqtt5ClientConfigBuilder.newDirectMqttBuilderWithMtlsFromPath(
    host,
    certPath + "/certificate.pem.crt",
    certPath + "/private.pem.key"
  );
builder.withConnectProperties({
  clientId: "0x7effff03",
  keepAliveIntervalSeconds: 60,
});


builder.withAckTimeoutSeconds(5);

const config = builder.build();

const client = new mqtt5.Mqtt5Client(config);

client.on("error", (e) =>
  console.log("ERRORRR", e.toString(), client.getOperationalStatistics())
);

client.on("attemptingConnect", (e) => console.log("attemptconnect", e));

client.on("connectionSuccess", (e) => console.log("success", e));

client.on("connectionFailure", (e) =>
  console.log("failure", e, client.getOperationalStatistics())
);

client.on("disconnection", (e) =>
  console.log("disconnect", e, client.getOperationalStatistics())
);

client.on("stopped", (e) => console.log("stopped", e));
(async () => {
  try {
    while (true) {
      client.start();
      const res = await client.publish({
        qos: mqtt5.QoS.AtLeastOnce,
        topicName,
        payload: "helloo",
        userProperties: [{'name': 'id', 'value': 'hehe'}]
      });
      console.log("queue", client.getOperationalStatistics());
      console.log("result", JSON.stringify(res));
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }
  } catch (err) {
    console.log("fatal", err);
  }
})();

output:

result {"type":4,"reasonCode":0,"userProperties":[]}

Links

https://aws.github.io/aws-iot-device-sdk-js-v2/node/interfaces/mqtt5.PublishPacket.html#userProperties

@dhyeyyyy dhyeyyyy added documentation This is a problem with documentation. needs-triage This issue or PR still needs to be triaged. labels May 22, 2024
@bretambrose
Copy link
Contributor

bretambrose commented May 22, 2024

The mqtt5 protocol does not establish any relationship between the user properties of a publish and its associated puback. For Iot Core (and probably every MQTT broker I'm aware of), publish user properties are only reflected in the publish packets sent to subscribers.

The only way to do direct correlation between publish and puback is by packet id.

Thinking about a persistence storage solution, it seems likely you'll need a system that associates unique ids with publishes and translates completed publish promises back to the persistence id.

@dhyeyyyy
Copy link
Author

There's no way to fetch this packet ID at the application layer?

@bretambrose
Copy link
Contributor

No. We don't allow it as an input so it doesn't make sense as an output.

Beyond that, packet ids come from a very small space (16 bits) and will be constantly reused over the course of a connection or session. They would make a terrible persistence key.

Making it correct is certainly more complicated than this, but supposing you have a durable key-value store of packets (say uuid -> publish-packet-as-json), it seems that just chaining on to the publish promise with a delete key operation (on success) would be reasonable (pseudocode):

async function durablePublish(kvStore: ??, key: string, client: Mqtt5Client) {
   let publishPacket = kvStore.get(key);
   publishPacket.qos = QoS.AtLeastOnce;
   let puback = await client.publish(packet);
   if puback.reasonCode == PubackReasonCode.Success {
      kvStore.delete(key);
   }
}

@dhyeyyyy
Copy link
Author

Got it- thanks so much :) !

Copy link

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation This is a problem with documentation. needs-triage This issue or PR still needs to be triaged.
Projects
None yet
Development

No branches or pull requests

2 participants