【问题标题】:How do you access the dead letter sub-queue on an Azure subscription?如何访问 Azure 订阅中的死信子队列?
【发布时间】:2014-03-27 08:26:41
【问题描述】:

当我使用以下内容时:

var deadLetterPath = SubscriptionClient.FormatDeadLetterPath(topicPath,subName);
var client = SubscriptionClient.CreateFromConnectionString(connectionString, deadLetterPath, subName);

我得到一个 InvalidOperationException

无法直接在子队列上创建客户端。在客户端创建一个 主队列并使用它在适当的位置上创建接收器 子队列

天蓝色文档的某些部分说使用 SubscriptionClient.CreateReceiver 来访问子队列,但该方法不存在。

【问题讨论】:

    标签: azure azure-servicebus-queues


    【解决方案1】:

    这种方法对你有用吗?

    MessagingFactory factory = MessagingFactory.CreateFromConnectionString(cnxString);
    var deadLetterPath = SubscriptionClient.FormatDeadLetterPath(topicPath,subName);
    var dlqReceiver = factory.CreateMessageReceiver(deadLetterPath, ReceiveMode.ReceiveAndDelete);
    

    我还没有在这里(在会议上)测试它,但试一试

    干杯

    【讨论】:

    • 做到了。我有点沮丧 MessageReceiver 和 SubscriptionClient 没有通用接口。我必须将它们包装在我自己的界面中,以便共享处理逻辑。
    • @kareem。 MessageReciever 继承/实现:MessageClientEntity、IMessageReceiver、IMessageBrowser。 SubscriptionClient 继承/实现:MessageClientEntity、IMessageSessionEntity、IMessageClientEntity、IMessageReceiver、IMessageBrowser。因此,您可能不需要将它们包装在您自己的界面中。我猜你可以使用 IMessageReciever 接口。
    • 没关系,很多都是内部的。然后你需要用反射来做。
    • 如果有人需要这个来阅读队列上的死信而不是主题:将第二行替换为var deadLetterPath = QueueClient.FormatDeadLetterPath(queueName)
    【解决方案2】:

    使用 Azure 服务总线对死信队列有一个约定命名:

    • 对于服务总线队列:queuePath/$DeadLetterQueue
    • 对于服务总线订阅:topicPath/subscriptionName/$DeadLetterQueue

    因此您可以像访问队列一样访问死信队列。

    从@SamVanhoutte 的回答可以看出,ServiceBus 框架提供了格式化死信队列名称的方法:

    • 对于服务总线队列:QueueClient.FormatDeadLetterPath(queuePath)

    • 对于服务总线订阅:SubscriptionClient.FormatDeadLetterPath(topicPath, subscriptionName)

    我写了两个小方法来为队列和订阅创建消息接收器,您可以在其中设置是否需要交易信队列:

    /// <summary>
    /// Create a new <see cref="MessageReceiver"/> object using the specified Service Bus Queue path.
    /// </summary>
    /// <param name="connectionString">The connection string to access the desired service namespace.</param>
    /// <param name="queuePath">The Service Bus Queue path.</param>
    /// <param name="isDeadLetter">True if the desired path is the deadletter queue.</param>
    public static MessageReceiver CreateMessageReceiver(string connectionString, string queuePath,
        bool isDeadLetter = false)
    {
        return MessagingFactory.CreateFromConnectionString(connectionString)
            .CreateMessageReceiver(isDeadLetter
                ? QueueClient.FormatDeadLetterPath(queuePath)
                : queuePath);
    }
    
    /// <summary>
    /// Create a new <see cref="MessageReceiver"/> object using the specified Service Bus Topic Subscription path.
    /// </summary>
    /// <param name="connectionString">The connection string to access the desired service namespace.</param>
    /// <param name="topicPath">The Service Bus Topic path.</param>
    /// <param name="subscriptionName">The Service Bus Topic Subscription name.</param>
    /// <param name="isDeadLetter">True if the desired path is the deadletter subqueue.</param>
    public static MessageReceiver CreateMessageReceiver(string connectionString, string topicPath,
        string subscriptionName, bool isDeadLetter = false)
    {
        return MessagingFactory.CreateFromConnectionString(connectionString)
            .CreateMessageReceiver(isDeadLetter
                ? SubscriptionClient.FormatDeadLetterPath(topicPath, subscriptionName)
                : SubscriptionClient.FormatSubscriptionPath(topicPath, subscriptionName));
    }
    

    【讨论】:

    • 我喜欢它的工作方式。只需将 +"/$DeadLetterQueue" 添加到订阅名称
    • 不要对它进行字符串破解。使用正确的 FormatDeadLetterPath 方法。
    • @granadaCoder 你是什么意思?此示例使用FormatDeadLetterPath 方法
    • 对不起。评论应该是“@Marat”,而不是你的 OP。
    【解决方案3】:

    如果您使用Microsoft.Azure.ServiceBus 而不是Microsoft.ServiceBus,则略有不同。

    var deadQueuePath = EntityNameHelper.FormatDeadLetterPath(your_queue_name);
    var deadQueueReceiver = new MessageReceiver(connectionString, deadQueuePath);
    

    根据 Microsoft.Azure.ServiceBus 命名空间中的 EntityNameHelper 类,对于主题,请使用订阅路径而不是 your_queue_name。

    队列的名称,或订阅的路径。

    /// <summary>
    /// Formats the dead letter path for either a queue, or a subscription.
    /// </summary>
    /// <param name="entityPath">The name of the queue, or path of the subscription.</param>
    /// <returns>The path as a string of the dead letter entity.</returns>
    public static string FormatDeadLetterPath(string entityPath)
    {
        return EntityNameHelper.FormatSubQueuePath(entityPath, EntityNameHelper.DeadLetterQueueName);
    }
    

    【讨论】:

      【解决方案4】:

      使用最新的服务总线客户端库,您可以像这样访问死信队列。请注意在创建接收器时指定死信队列时语言之间的一致性:

      const { ServiceBusClient } = require("@azure/service-bus");
      
      const client = new ServiceBusClient("<connectionstring>");
      const deadletterReceiver = client.createReceiver("queueName", { subQueueType: "deadLetter" });
      const messages = await deadletterReceiver.receiveMessages(1);
      
      if (messages.length > 0) {
          console.log("Received the message from DLQ - ", messages[0].body);
      
          // Mark message as complete, i.e. remove from DLQ
          await deadletterReceiver.completeMessage(messages[0]);
      } else {
          console.log("Error: No messages were received from the DLQ.");
      }
      
      await deadletterReceiver.close();
      
      import com.azure.messaging.servicebus.*;
      import com.azure.messaging.servicebus.models.SubQueue;
      
      ServiceBusReceiverClient deadletterReceiver = new ServiceBusClientBuilder()
          .connectionString("<connectionstring>")
          .receiver() // Use this for session or non-session enabled queue or topic/subscriptions
          .queueName("queuename")
          .subQueue(SubQueue.DEAD_LETTER_QUEUE)
          .buildClient();
      
      IterableStream<ServiceBusReceivedMessage> messages = receiver.receiveMessages(10);
      messages.forEach(message -> {
          System.out.printf("Id: %s. Contents: %s%n", message.getMessageId(),
              message.getBody().toString());
      
          //Remove message from DLQ
          deadletterReceiver.complete(message);
      });
      
      deadletterReceiver.close();
      
      import asyncio
      from azure.servicebus import ServiceBusMessage, ServiceBusSubQueue
      from azure.servicebus.aio import ServiceBusClient
      
      servicebus_client = ServiceBusClient.from_connection_string(conn_str="<connectionstring>")
      dlq_receiver = servicebus_client.get_queue_receiver(queue_name="queuename", 
                     sub_queue=ServiceBusSubQueue.DEAD_LETTER)
      
      async with dlq_receiver:
          received_msgs = await dlq_receiver.receive_messages(max_message_count=10, max_wait_time=5)
          for msg in received_msgs:
              print(msg)
              
              # remove the message from the DLQ
              await dlq_receiver.complete_message(msg)
      
      
      using Azure.Messaging.ServiceBus;
      
      await using var client = new ServiceBusClient("<connectionstring>");
      ServiceBusReceiver deadletterReceiver = client.CreateReceiver(
          "queuename",
           new ServiceBusReceiverOptions { SubQueue = SubQueue.DeadLetter }
      );
      
      ServiceBusReceivedMessage message = await deadletterReceiver.ReceiveMessageAsync();
                  
      if (message != null)
      {
          Console.WriteLine($"DeadLetter message = {message.Body}");
          
          // remove the message from the DLQ
          await deadletterReceiver.CompleteMessageAsync(message);
      }
      else
      {
          // DLQ was empty on last receive attempt
          Console.WriteLine("Error: No messages were received from the DLQ."); 
      }
      
      await deadletterReceiver.CloseAsync(); 
      

      【讨论】:

      • 多么专业。不仅可以用一种语言回答,而且可以用 4 种不同的语言回答。
      【解决方案5】:

      那些想用python做的人。

      接收来自死信队列的消息:

      from azure.servicebus import ServiceBusClient
      import json
      connectionString = "Your Connection String to Service Bus"
      serviceBusClient = ServiceBusClient.from_connection_string(connectionString)
      queueName = "Your Queue Name created in the Service Bus"
      queueClient = serviceBusClient.get_queue(queueName)
      with queueClient.get_deadletter_receiver(prefetch=5) as queueReceiver:
          messages = queueReceiver.fetch_next(timeout=100)
          for message in messages:
              # message.body is a generator object. Use next() to get the body.
              body = next(message.body)
              message.complete()
      

      希望对某人有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-04
        • 2021-04-11
        • 1970-01-01
        • 2021-07-19
        • 2016-08-30
        • 2018-04-01
        • 2017-08-13
        相关资源
        最近更新 更多