有没有一种方法可以在 Azure 服务总线中使用代理消息来定位特定主题订阅者?

Is there a way to target a particular topic subscriber with brokered messaging in Azure Service Bus?

首先是我的具体问题

假设我有 3 个订阅者订阅了一个主题,但我只想针对一个特定的订阅者;这可以做到吗?

我想要完成的事情

收听主题的订阅者将处理消息,其中可能包括数据库访问(并且数据库可能暂时关闭)。当出现问题时,我希望能够在以后重新处理。

我知道我们可以使用 Defer() 稍后处理,但是它需要您保存消息 ID。很明显,如果数据库已关闭,我无法保存在那里,所以如果我想持久保存,我必须保存到另一个数据存储。

如果 "other datastore" 是服务总线,那么我似乎必须为我的每个订阅者创建主题,这似乎有点难以管理。我的计划是将失败的请求发送到主题的死信队列。计划任务将定期到来,并从每个主题的 DLQ 中取出消息并尝试处理。如果它再次失败,我想重新提交消息并增加一个 "AttemptedTries" 计数器,它是消息本身的一部分。如果我可以只针对相关订阅者,这样没有问题的主题订阅者就不必处理,我会喜欢它(如果此功能不可用,我可能会添加过滤器或其他东西来完成类似的事情)。

尝试次数 >= maxattempts 后,我会将消息发送到通用 "graveyard"(非特定主题),程序员可以在其中决定如何处理消息。

这样处理好吗? ASB 是否内置了一些这样的东西?

您不能向特定订阅者发送消息,但您可以 "target it" 通过在消息上标记 header/value 特定订阅者过滤的标记。

现在针对您的情况 - 我强烈建议不要将消息传递用作存储。空队列是快乐队列。并且绝对不要为此目的使用 DLQ。它具有指定的作用,应该用于该目的。

我建议研究您的消息延迟,并使用原子操作(ASB 事务),如果您不想处理消息,您可以简单地生成一条新消息并将其排入队列以供将来处理序列号。这也将消除在处理 DLQ 时额外计划任务和不必要的复杂性的需要。

我认为按照您描述的方式使用 DLQ 没有任何问题。事实上,这就是 DLQ 的(部分)用途:

The purpose of the dead-letter queue is to hold messages that cannot be delivered to any receiver, or simply messages that could not be processed. Messages can then be removed from the DLQ and inspected. An application might, with help of an operator, correct issues and resubmit the message, log the fact that there was an error, and/or take corrective action.

https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues

关于过滤器:ASB 提供各种订阅过滤器(SQL 过滤器是最灵活的),因此您可以使用它们将消息(基于元数据等)匹配到订阅者。

如果您使用过滤器,请考虑使用单个错误队列(您称之为墓地),所有失败的消息都放在这里。 IMO 从一个地方监视、检查和重新处理事物可能比处理无数的 DLQ 更简单。在这种情况下,一条失败的消息需要用订阅名称(失败的消息)之类的东西来标记,这样当它被重新发送时,只有那个消息会尝试处理。

为了添加到组合中,我将添加我发现的内容。您可以通过 BrokeredMessage 的 "To" 属性 联系特定订阅者。

订户将需要过滤器(不确定为什么这不是自动的);您可以使用 CorrelationFilter 例如

var filter = new CorrelationFilter {To="mySubscriber"};

或者,在我的例子中,我正在寻找“将所有直接发送给我或所有订阅者的消息发送给我。我通过 SqlFilter 完成了这个,

 new SqlFilter($"sys.To IS NULL OR sys.To = '{_subscriptionName}'")

请注意 "sys" 的使用,因为 "To" 是 BrokeredMessage 的 属性。