Search code examples
javascriptazure-functionsazureservicebusdead-letter

Handling service bus error messages in azure function using javascript


I have an azure function using service bus topic trigger and I want to handle error messages gracefully, I want to be able to do an abandon of the message and pass the exception to it so I can see it in a property when I read the dead letters queue.

this is my code:

const serviceBusTopicTrigger: AzureFunction = async function(context: Context, mySbMsg: any): Promise<void> {
    // do something messy that may fail.
};

When my function fails with an exception the message goes to the DLQ as expected, but the problem is, that it doesn't save the exception thrown, it only tells you that it tried to execute the method 10 times and it couldn't.

What I want its to be able to catch the exception and add it to the message properties so, when I process the DLQ queue I will be able to know the reason for the error. Even more, as the code is failing with an exception I would like it to abandon from the first time it runs the message, so it doesn't have to retry 10 times.

I'm thinking something like this:

const serviceBusTopicTrigger: AzureFunction = async function(context: Context, mySbMsg: any): Promise<void> {
    try{
        // do something messy and that may fail
    }
    catch(error){
        context.bindingData.userProperties['DeadLetterReason'] = 'Internal server error';
        context.bindingData.userProperties['DeadLetterErrorDescription'] = JSON.stringify(error);
        context.bindingData.abandonMsg();
    } 
};

I haven't been able to find any documentation about something like this, so is it possible? or can I force the message to the DLQ? with something like this:

const serviceBusTopicTrigger: AzureFunction = async function(context: Context, mySbMsg: any): Promise<void> {
    try{
        // do something messy and that may fail
    }
    catch(error){
        context.bindings.deadLetterQueue.userProperties['DeadLetterReason'] = 'Internal server error';
        context.bindings.deadLetterQueue.userProperties['DeadLetterErrorDescription'] = JSON.stringify(error);
        context.bindings.deadLetterQueue = mySbMsg;
    } 
};

Or finally and sadly do I have to manage my error directly from the method and maybe send it directly from there to an azure storage table or queue to notify errors?, I wouldn't like that because then I would be handling, both errors from the dead letter queue, and from my functions in different places. Is this the only way?

Any more ideas?

Thanks.


Solution

  • First of all, I think nodejs can not do this. nodejs lost the type information in C#, it should have been sent like this:

    https://learn.microsoft.com/en-us/dotnet/api/microsoft.servicebus.messaging.brokeredmessage.deadletterasync?view=azure-dotnet

    When my function fails with an exception the message goes to the DLQ as expected, but the problem is, that it doesn't save the exception thrown, it only tells you that it tried to execute the method 10 times and it couldn't.

    Max Delivery Count is set to 10 by default when you create the subscription of the service bus topic. The default value is 10, and the minimum can be set to 1.

    When you turn on the service bus information automatic completion, just like below:

    host.json

    {
      "version": "2.0",
      "extensions": {
        "serviceBus": {
          "messageHandlerOptions": {
            "autoComplete": true
          }
        }
      },
      "logging": {
        "applicationInsights": {
          "samplingSettings": {
            "isEnabled": true,
            "excludedTypes": "Request"
          }
        }
      },
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 3.1.0)"
      }
    }
    

    At that time, when an error occurs, the function run failed, call the abandon method, Delivery Count +1, and send the message back at the same time.

    Then once you use try-catch, you will not retry 10 times at all. The function is regarded as a successful operation, function run success and the message disappears without sending it back.(That is, once try-catch you will only execute it once.)

    I haven't been able to find any documentation about something like this, so is it possible? or can I force the message to the DLQ?

    No, it can't be done. The related type is missing and cannot be manually sent to dead-letter via JavaScript.

    Or finally and sadly do I have to manage my error directly from the method and maybe send it directly from there to an azure storage table or queue to notify errors?, I wouldn't like that because then I would be handling, both errors from the dead letter queue, and from my functions in different places. Is this the only way?

    Why do you say that the error still appears in the dead-letter? Using try-catch in the case of automatic completion should not be sent to dead-letter.