Question

I'm writing a piece of code which will allow us to:

  1. View a list of all dead letter messages that exist within an Azure Service Bus Topic (Peek)
  2. Fix and send them back to the Topic
  3. Delete them from the dead letter queue upon resending.

I have no issues with the first 2 points; using the Peek receive mode I can show a list of messages and we can edit and resend with no issues.

The problem comes when I want to actually delete the message from the dead letter queue.

How do we do this on a message by message level? We may only want to delete 2 of the messages residing in the dead letter queue and keep the others for reviewing at a later stage. Does calling .Complete() on a message in the dead letter queue remove it like it does in the main subscription?

For reference; here is our code for getting the SubscriptionClient for the dead letter queue:

private SubscriptionClient GetOrCreateSubscriptionClient(string connectionString)
{
    if (!NamespaceManager.TopicExists(_topicName))
    {
        NamespaceManager.CreateTopic(new TopicDescription(_topicName)
        {
            MaxSizeInMegabytes = 5120,
            DefaultMessageTimeToLive = TimeSpan.FromSeconds(DEFAULT_LOCK_DURATION_IN_SECONDS)
        });
    }

    if (!NamespaceManager.SubscriptionExists(_topicName, _subscriptionName))
    {
        NamespaceManager.CreateSubscription(_topicName, _subscriptionName);
    }

    var deadLetterPath = SubscriptionClient.FormatDeadLetterPath(_topicName, _subscriptionName);

    var client = SubscriptionClient.CreateFromConnectionString(
        connectionString, deadLetterPath, _subscriptionName, ReceiveMode.PeekLock);

    return client;

}
Was it helpful?

Solution

Yes, calling complete on the reference to the brokered message you receive from the dead letter queue will remove it from the dead letter queue.

OTHER TIPS

Here is how you can get a list of all messages in the dead letter queue:

public async Task<IEnumerable<BrokeredMessage>> GetDeadLetterMessagesAsync(string connectionString,
    string queueName)
{
    var queue = QueueClient.CreateFromConnectionString(connectionString, QueueClient.FormatDeadLetterPath(queueName));
    var messageList = new List<BrokeredMessage>();
    BrokeredMessage message;
    do
    {
        message = await queue.PeekAsync();
        if (message != null)
        {
            messageList.Add(message);
        }
    } while (message != null);
    return messageList;
}

Using the SequenceNumber you can then delete a specific message:

public async Task DeleteDeadLetterMessageAsync(string connectionString, string queueName, long sequenceNumber)
{
    var deadLetterQueue = QueueClient.CreateFromConnectionString(connectionString, QueueClient.FormatDeadLetterPath(queueName));
    var msg = await deadLetterQueue.PeekAsync(sequenceNumber);
    if (msg.SequenceNumber == sequenceNumber)
    {
        msg = await deadLetterQueue.ReceiveAsync();
        await msg.CompleteAsync();
    }
}

Please note that Peek may return another message if there isn't any message with the specified SequenceNumber. Therefore you'll need to check the SequenceNumber, so that you don't delete the wrong message.

Updated code to delete a message from the dead letter queue using the new ServiceBusClient from azure.messaging.servicebus:

public async Task DeleteDeadLetterMessageAsync(string connectionString, string queueName, long sequenceNumber)
{
    var serviceBusClient = new ServiceBusClient(connectionString);
    var receiverOptions = new ServiceBusReceiverOptions { SubQueue = SubQueue.DeadLetter };
    var receiver = serviceBusClient.CreateReceiver(queueName, receiverOptions);
    var msg = await receiver.PeekMessageAsync(sequenceNumber);
    if (msg.SequenceNumber == sequenceNumber)
    {
        msg = await receiver.ReceiveMessageAsync();
        await receiver.CompleteMessageAsync(msg);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top