How to manually handle message completion in C# azure function with azure service bus 5.0.0

Viewed 2685

I'm writing an Azure Function to get the messages in an Azure Service Bus. I want to handle any exceptions manually ("autoCompleteMessages": false) Can't figure how to send the complete or abandon back to the service queue.

Tried Option 1:

[FunctionName("SBQ_F1_VC")]
public static async Task Run([ServiceBusTrigger("sbqfn1", Connection = "BrnlTest1_SERVICEBUS")]
    ServiceBusReceivedMessage msg, ILogger log)
{
//.....

    if(!Int32.TryParse(msg.ApplicationProperties.GetValueOrDefault("vid").ToString(), out vid))
    {   await using ServiceBusClient client = new ServiceBusClient(Environment.GetEnvironmentVariable("BrnlTest1_SERVICEBUS"));
        ServiceBusReceiver msgRcvr = client.CreateReceiver(Environment.GetEnvironmentVariable("queueName"), new ServiceBusReceiverOptions()); 
        //await msgRcvr.RenewMessageLockAsync(msg);
        await msgRcvr.AbandonMessageAsync(msg);  //vid = 0;
    }

//.....
}

Errors Option 1

System.Private.CoreLib: Exception while executing function: SBQ_F1_VC. Azure.Messaging.ServiceBus: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue, or was received by a different receiver instance. (MessageLockLost).

Tried Option 2:

[FunctionName("SBQ_F1_VC")]
        public static async Task Run([ServiceBusTrigger("sbqfn1", Connection = "BrnlTest1_SERVICEBUS")]
         ServiceBusReceivedMessage[] msgs,
         ServiceBusMessageActions msgActions)
        {
        //.....
        await msgActions.DeadLetterMessageAsync(msg);
        
        }

Errors Option 2:

Microsoft.Azure.WebJobs.Host: Error indexing method 'SBQ_F1_VC'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'msgActions' to type ServiceBusMessageActions. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

Notes:

  • Service Bus is 5.0.0 so I have to use Azure.Messaging.ServiceBus namespace
    • This implies the message object is ServiceBusReceivedMessage

What worked (based on Jesse's and Josh's answers)

The Parameter Name for ServiceBusMessageActions MUST be messageActions.
Changing this name is not tolerated for some reason...

public static async Task Run(
        [ServiceBusTrigger("sbqfn1", Connection = "BrnlTest1_SERVICEBUS")]
        ServiceBusReceivedMessage[] msgs,
        ServiceBusMessageActions messageActions)
        {
2 Answers

You will need to use "messageActions" as the parameter name rather than "msgActions".

Locks are only valid on the AMQP link that the message was received from. In order to manually settle messages, you'll need to bind your trigger to the ServiceBusMessageActions. Those actions can be used for message settlement.

For example:

[FunctionName("BindingToMessageActions")]
public static async Task Run(
    [ServiceBusTrigger("<queue_name>", Connection = "<connection_name>")]
    ServiceBusReceivedMessage[] messages,
    ServiceBusMessageActions messageActions)
{
    foreach (ServiceBusReceivedMessage message in messages)
    {
        if (message.MessageId == "1")
        {
            await messageActions.DeadLetterMessageAsync(message);
        }
        else
        {
            await messageActions.CompleteMessageAsync(message);
        }
    }
}

Related