通过MessageId在Azure Service Bus死信队列上获取消息

时间:2013-12-05 09:35:59

标签: c# azure azureservicebus

我正在编写用于监控和修复Azure上dead letter queue的{​​{1}}消息的功能。

我可以使用topic subscription来显示消息列表;但是当我们想要删除其中一条消息时,我们就会陷入困境。

工作流程将是:

  1. 获取所有消息的列表
  2. 将特定消息(比如集合中的第5个消息)发送回原始队列以进行重新处理
  3. 将关联的死信消息标记为_subscriptionClient.PeekBatch(10)
  4. 问题在于,虽然我们收到了邮件列表,但我们无法在不使用.Complete()的情况下就特定邮件调用.Complete()

    由于你不能通过MessageId .subscriptionClient.Receive()发送消息,这是否意味着我们必须像下面一样逐个遍历消息?

    .Receive()

    我对这种方法的问题是:

    • 它不可扩展;如果消息是集合中的第100个怎么办?我们必须循环99并将每个标记为已放弃
    • 如果有太多要放弃的项目,我们可能会失去public BrokeredMessage GetMessageById(string messageIdentifier) { BrokeredMessage matchingMessage = null; var messageNotFound = true; var messagesToAbandon = new List<BrokeredMessage>(); while (messageNotFound) { var message = _subscriptionClient.Receive(); if (message == null) { throw new Exception("Could not find the message on the queue"); } if (message.MessageId == messageIdentifier) { messageNotFound = false; matchingMessage = message; } else { messagesToAbandon.Add(message); } } // Unlock all messages that do not match the matching one received. foreach (var message in messagesToAbandon) { message.Abandon(); } return matchingMessage; } 上的锁定
    • 这是一个漫长的过程

    如果在循环内没有匹配,我已经玩弄了将每条消息标记为已放弃的想法;但是这会产生我们无限循环遍历相同项目的风险(因为matchingMessage将它们放回队列中)。

    有没有人找到一个有效的方法呢?也许将.Abandon().Defer()一起使用?

3 个答案:

答案 0 :(得分:4)

您可以在此处使用会话,为每条消息设置会话ID。稍后当您浏览DeadLetter时,选择消息及其sessionID,使用sessionID打开会话并接收消息。

<强>更新: 作为特殊队列的DeadLetter队列不允许会话,并且也不能使用sequenceNumber从DeadLetter队列接收消息,如果您想要选择消息,这些是我找到的两个选项。

所以这是在问题描述的情况下应该做什么,从DeadLetter获取所有消息,将某些消息重播到原始队列进行重新处理,将其余消息移动到另一个队列( ErrorQueue)并清除死信队列。 我认为这更合适,因为DeadLetter队列更像是ServicBus处理错误/到期的内部队列。如果应用程序需要处理错误,那么将它们移动到特定于应用程序的队列将提供更大的灵活性,而不是过度加载系统队列(DeadLetter Queue)

答案 1 :(得分:1)

我们和Dhana Krishnamsamy一样。

我们创建了一个DeadLetterQueueCompanionQueue 然后,对于每个订阅,我们为deadletter queue注册了一个客户端 该客户端将原始消息的副本重新提交到新队列

我们的队列有一个消息到期,也允许我们在一个地方进行监控。

然后我们在原始的死信队列中完成消息。

答案 2 :(得分:1)

如果您有消息SequenceNumber:

,您可以非常简单地从死信队列中删除特定消息
public static void DeleteDeadLetterMessage(string connectionString, string queueName, long sequenceNumber)
{
    var deadLetterQueue = QueueClient.CreateFromConnectionString(connectionString, QueueClient.FormatDeadLetterPath(queueName));
    var msg = deadLetterQueue.Peek(sequenceNumber);
    if (msg.SequenceNumber == sequenceNumber)
    {
        msg = deadLetterQueue.Receive();
        msg.Complete();
    }
}

唯一需要注意的是,如果没有任何带有指定SequenceNumber的消息,Peek可能会返回另一条消息。

因此,您需要检查SequenceNumber,以便您不会完成错误的消息。