Azure/azure-sdk-for-net

[QUERY] How to properly acknowledge IoT hub messages

the-programmer opened this issue · 1 comments

Library name and version

Microsoft.Azure.Devices 1.39.1

Query/Question

Project overview

In my current project I need to control embedded devices (running the Azure SDK for C V1.1.6 on an ESP32, using MQTT) via Azure IoT hub.
So far I managed to get the Device to Cloud (D2C) and Cloud to Device (C2D) functionality working without issues.

The current communication flow for D2C messages is as follows and works great.

  • The device sends a message to the IoT hub via MQTT.
  • IoT hub writes directly to a CosmosDB container.
  • An Azure function has a CosmosDBTrigger on this container.
  • The function decodes the body and stores there result in a different container. (This is done to base64 decode the Body of the message)

The current communication flow for C2D messages is as follows and is giving some issues.

  • The front-end writes to a CosmosDB container
  • An Azure function has a CosmosDBTrigger on this container.
  • The function prepares the message and transmits it to IoT hub.
  • IoT hub sends the message to the device via MQTT.

Finally, there is a timed Azure function to parse all the feedback from the IoT hub. The feedback is than used to update the container that contained the original command.
This is a timed function since Azure functions doe not allow the "normal" while(true) method due to a maximum runtime of 5 minutes. This method is inspired by this article.

Some additional details

Program.cs

In the program.cs of the Azure functions I registered the IoT hub client as follows

//Get the connectionstring for the iotHubServiceClient and create an instance
var iotHubConnectionString = Environment.GetEnvironmentVariable("IotHubConnectionString", EnvironmentVariableTarget.Process);
var iotHubServiceClient = ServiceClient.CreateFromConnectionString(iotHubConnectionString);

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
       //Other code
        
        //Add the IotHub Serviceclient
        services.AddSingleton(iotHubServiceClient);
    })
    .Build();

When it started

Before setting the Ack to DeliveryAcknowledgement.Full I didn't notice this issue (and as far as I can tell it wasn't there).

Timed function code

The timed function had got the following code

//Get the feedbackReceiver
var feedbackReceiver = _iotHubServiceClient.GetFeedbackReceiver();

//Create a cancellationToken with a timeout of 1 minute
var timeoutCancellationTokenSource = new CancellationTokenSource(new TimeSpan(0, 1, 0));

//Start waiting for new messages
var message = await feedbackReceiver.ReceiveAsync(timeoutCancellationTokenSource.Token);
_logger.LogInformation("Got {count} status messages from IoT hub", message?.Records.Count() ?? 0);

//Did we get anything
if (message == null)
    //No, abort here
    return;

//Update the statuscode in the database
//[...]

//Complete all the received messages
var cancellationTokenSource = new CancellationTokenSource();
await feedbackReceiver.CompleteAsync(message, cancellationTokenSource.Token);

The issue

The function that sends the message to the IoT hub has the following code.

 var message = new Message(Encoding.ASCII.GetBytes(JsonSerializer.Serialize(commands)))
 {
     Ack = DeliveryAcknowledgement.Full,
     MessageId = command.Id,
 };

 await _iotHubServiceClient.SendAsync(deviceId, message);

So, when the front-end now inserts a new document into the command container the message is correctly transmitted to the device (via MQTT). It seems that the command get's "stuck" somewhere in transmission. My device keeps on receiving duplicate MQTT messages that have been received already.

My timed function also had this issue. It keeps on getting the acknowledgements for the same message over and over.

I would really like to have full acknowledgement sine this is the only way for the operators to get (delayed) feedback.

Environment

Hosting platform: Azure function app, .NET 8 (LTS), isolated worker model, windows. Runtime version 4.30.0.22097
Microsoft Visual Studio Professional 2022 (64-bit) Version 17.9.2

This issue has been transferred to the repository where the Microsoft.Azure.Devices library is maintained as #3438.