Azure Service Bus队列消息留存及指定接收方出队问题咨询
问题1:如何从Queue中获取消息但让消息一直留存直至其TTL到期
你的测试异常大概率是使用了默认的ReceiveAndDelete接收模式,该模式下消息只要被消费者拉取就会直接从队列移除,和是否调用CompleteMessageAsync无关。
要实现你的需求有两种可选方案:
- 仅需读取消息内容、不需要锁定消息避免其他消费者读取:直接调用
PeekAsync方法读取消息,该操作为只读操作,不会修改队列中消息的任何状态,消息会一直留存直到自身TTL到期自动删除。 - 需要临时锁定消息避免其他消费者拉取:将接收模式改为
PeekLock模式,拉取到消息后不要调用CompleteMessageAsync、DeadLetterMessageAsync等会移除消息的方法,等消息锁到期后会自动重回队列,循环该过程直到消息TTL到期自动删除。
问题2:如何实现从Queue中获取消息时,仅当消息被指定接收方收到时才将其出队
核心实现逻辑配合PeekLock接收模式即可完成,具体方案如下:
- 所有消费者统一使用
PeekLock模式从队列拉取消息 - 消费者拿到消息后先校验自定义属性
ReceiverId是否匹配自身ID:- 匹配成功:完成业务逻辑处理后调用
CompleteMessageAsync方法,消息会从队列正式移除 - 匹配失败:立即调用
AbandonMessageAsync方法主动释放消息锁,消息会立刻回到队列供其他消费者拉取
- 匹配成功:完成业务逻辑处理后调用
参考实现代码:
// 当前接收方的ID const string CurrentReceiverId = "123"; // 用PeekLock模式创建消息接收器 var receiver = serviceBusClient.CreateReceiver(queueName, new ServiceBusReceiverOptions { ReceiveMode = ServiceBusReceiveMode.PeekLock }); var receivedMessage = await receiver.ReceiveMessageAsync(); if (receivedMessage != null) { // 校验ReceiverId是否匹配 if (receivedMessage.ApplicationProperties.TryGetValue("ReceiverId", out var receiverIdObj) && receiverIdObj?.ToString() == CurrentReceiverId) { // 匹配成功,处理业务逻辑 // ... // 处理完成后确认消息,将其从队列移除 await receiver.CompleteMessageAsync(receivedMessage); } else { // 匹配失败,释放消息锁 await receiver.AbandonMessageAsync(receivedMessage); } }
如果希望降低无关消费者拉取错误消息的概率,也可以使用ASB队列的会话功能:发送消息时将ReceiverId设置为消息的SessionId,消费时每个接收方只拉取对应SessionId的消息即可。
内容的提问来源于stack exchange,提问作者user2296256
相关产品推荐
相关产品推荐

