考虑以下场景:启用了重复数据删除的 Azure 服务总线,具有单个主题、单个订阅和订阅该队列的应用程序。
如何确保应用程序从队列中接收消息一次且仅一次?
这是我在应用程序中用于接收消息的代码:
public abstract class ServiceBusListener<T> : IServiceBusListener
{
private SubscriptionClient subscriptionClient;
// ..... snip
private void ReceiveMessages()
{
message = this.subscriptionClient.Receive(TimeSpan.FromSeconds(5));
if (message != null)
{
T payload = message.GetBody<T>(message);
try
{
DoWork(payload);
message.Complete();
}
catch (Exception exception)
{
// message.Complete failed
}
}
}
}
我预见的问题是,如果message.Complete()
由于某种原因失败,那么刚刚处理的消息将保留在 Azure 中的订阅队列中。再次ReceiveMessages()
调用时,它将从队列中获取相同的消息,并且应用程序将再次执行相同的工作。
虽然最好的解决方案是具有幂等域逻辑 ( DoWork(payload)
),但在这种情况下很难编写。
我能看到的确保一次且仅一次交付给应用程序的唯一方法是构建另一个队列以充当 Azure 服务总线和应用程序之间的中介。我相信这被称为“持久的客户端队列”。
但是我可以看到这对于许多使用 Azure 服务总线的应用程序来说是一个潜在的问题,那么持久的客户端队列是唯一的解决方案吗?