【问题标题】:Getting a Message by MessageId on the Azure Service Bus Dead Letter queue通过 Azure 服务总线死信队列上的 MessageId 获取消息
【发布时间】:2013-12-05 09:35:58
【问题描述】:

我正在编写用于监视和修复 Azure 上 topic subscriptiondead letter queue 中的消息的功能。

我可以使用_subscriptionClient.PeekBatch(10) 获取消息列表进行显示;但是,当我们想要真正删除其中一条消息时,我们就卡住了。

工作流程是:

  1. 获取所有消息的列表
  2. 将特定消息(例如集合中的第 5 条消息)发送回原始队列以进行重新处理
  3. 将关联的死信消息标记为.Complete()

问题在于,虽然我们有消息列表,但如果不先使用 .subscriptionClient.Receive(),我们就无法在特定消息上调用 .Complete()

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

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;
}

我对这种方法的问题是:

  • 它不可扩展;如果消息是集合中的第 100 条消息怎么办?我们必须遍历 99 个并将每个标记为废弃
  • 如果要放弃的项目太多,我们可能会失去对 matchingMessage 的锁定
  • 这是一个长期运行的过程

如果在循环中不匹配,我已经考虑过将每条消息标记为已放弃的想法;然而,这会产生我们无限循环相同项目的风险(因为.Abandon() 将它们放回队列中)。

有没有人找到解决这个问题的有效方法?也许将.Defer().Receive(sequenceNumber) 一起使用?

【问题讨论】:

    标签: c# azure azureservicebus


    【解决方案1】:

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

    更新: DeadLetter 队列是一个特殊的队列,它不允许会话,也无法使用 sequenceNumber 从 DeadLetter 队列接收消息,如果你想挑选消息,我发现了这两个选项。

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

    【讨论】:

    • 听起来很有趣 Dhana;在发送到原始队列之前,您是否必须在每条消息上设置SessionID
    • 抱歉,会话没有按照我的解释进行。我已经用我发现的内容更新了我的答案,并认为对你的情况有帮助。
    • 很好的建议;那么您可以根据需要使用自定义SessionID 和樱桃选择将每条消息发送到新的错误队列吗?
    • 是的,您可以使用会话/过滤器(添加新属性)/序列号来挑选消息。
    【解决方案2】:

    如果您有消息序列号,则可以非常简单地从死信队列中删除特定消息:

    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,以免填写错误消息。

    【讨论】:

      【解决方案3】:

      我们和 Dhana Krishnamsamy 一样。

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

      我们的队列有消息过期时间,还允许我们在一个地方进行监控。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-01
        • 1970-01-01
        • 2017-02-13
        • 2014-06-30
        • 2017-06-07
        • 2020-09-07
        相关资源
        最近更新 更多