Search code examples
c#.netazureazure-functionsazure-queues

Why is my Queue trigger sending messages to <queue-name>-poison queue when it is exectued?


I'm trying to send data from a console application from a local machine to an Azure Storage Queue. When I run the console app locally, my data successfully gets stored in the queue. The issue is that I am trying to create a queue trigger when the information is added. The max dequeue limit keeps on getting reached and the data is stored in the -poison queue. The queue trigger will be used to send the data to a database but, for now I've been testing if the queue trigger is being executed correctly which hasn't been the case.

Here's the console app code:

try 
{ 
    // Instantiate a QueueClient which will be used to create and manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, "queue-name");

    //Creates a queue if it doesn't exists
    queueClient.CreateIfNotExists();

    //Checks If the queue exists
    if (queueClient.Exists())
    {
        Console.WriteLine($"Queue created: '{queueClient.Name}'");
        Console.WriteLine("Enter A Message: ");
        string message = Console.ReadLine();

        //Sends the message to the queue
        queueClient.SendMessage(message);

        Console.WriteLine($"Message {message} sent to Queue");
    }
    else
    {
        Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Exception: {ex.Message}\n\n");
    Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
}

Here's the Queue Trigger code:

    public void Run([QueueTrigger("queue-name", Connection = "StorageAccountString")]string myQueueItem, ILogger log)
        {
            log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
        }
    }

The output when Queue Trigger is executed:

Executed 'Function1' (Failed, Id=2794af0b-38fe-43e5-aab9-e2d0fc4cf7d2, Duration=126ms) [2022-10-06T19:22:50.982Z] System.Private.CoreLib: Exception while executing function: Function1. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'myQueueItem'. System.Private.CoreLib: Unable to translate bytes [EB] at index 1 from specified code page to Unicode.

Message has reached MaxDequeueCount of 5. Moving message to queue 'cldv6212-poe-task2-queue-poison'.


Solution

  • The Message which you are adding to the queue must be base64 encoded or must be in a format that can be included in an XML request with UTF-8 encoding.

    Try the below code:

    try 
    { 
        
        QueueClient queueClient = new QueueClient(connectionString, "queue-name");
    
        queueClient.CreateIfNotExists();
    
        if (queueClient.Exists())
        {
            Console.WriteLine($"Queue created: '{queueClient.Name}'");
            Console.WriteLine("Enter A Message: ");
            string message = Console.ReadLine();
            var bytes = Encoding.UTF8.GetBytes(message);
            await queueClient.SendMessageAsync(Convert.ToBase64String(bytes));
            Console.WriteLine($"Message {message} sent to Queue");
        }
        else
        {
            Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}\n\n");
        Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
    }
    

    I also have tried the same manually as alternative and got the expected result:

    • Create storage account in Azure Portal.

    • Create new project in VS Code.(Select Azure functions->QueueTrigger).

    • Open storage account and copy connection string.

    • Add the connection string to local.setting.json in vs code.

    • Create Queue in storage account. Open the Queue, click on Add Message to add the message to the Queue. Enable base 64 as shown below: enter image description here

    • Run the code in VS.

    Output: enter image description here

    when a trigger function exceeds 5 retry requests, queue storage will move the messages to poison queue. enter image description here

    Thanks to Aditya Pendharkar for the blog to handle the failed messages:

    1. Use the ‘DequeueCount’ property of the CloudQueueMessage to check the number of times the message has been dequeued.If that number passes a certain threshold you can log the message with details of the failure. This threshold has to be less than or equal to 5 by default. In case you want to change the number of times the message is retried you can update the ‘maxDequeueCount’ property in the ‘host.json’ file. Using this option would avoid the message being added to a poison queue.
    2. Alternatively you can let the message be added to the poison queue and add another function that is triggered whenever a message is added to the poison queue. You can do the logging in this function instead of doing it directly in the main function that processes the message.