C# 未超过锁定持续时间时,Azure服务总线为非分区队列抛出MessageLockLostException
我正在尝试使用C# 未超过锁定持续时间时,Azure服务总线为非分区队列抛出MessageLockLostException,c#,azure,azureservicebus,C#,Azure,Azureservicebus,我正在尝试使用PeekLockreceive模式接收消息,处理消息(处理时间远低于消息锁定持续时间),然后完成消息。我已经检查了周围是否有类似的问题,但我想我已经排除了所有建议的解决方案 队列未分区 当我进行测试时,队列上只有一条消息,我甚至尝试将PrefetchCount设置为1 只有一个接收器处于活动状态 我已将锁定持续时间增加到5分钟,处理时间约为20秒。检查收到的消息时,我可以看到LockedUntil属性比CompleteAsync调用晚得多 即便如此,每次调用CompleteAs
PeekLock
receive模式接收消息,处理消息(处理时间远低于消息锁定持续时间),然后完成消息。我已经检查了周围是否有类似的问题,但我想我已经排除了所有建议的解决方案
- 队列未分区
- 当我进行测试时,队列上只有一条消息,我甚至尝试将
设置为1PrefetchCount
- 只有一个接收器处于活动状态
- 我已将
锁定持续时间增加到5分钟,处理时间约为20秒。检查收到的消息时,我可以看到
属性比LockedUntil
调用晚得多CompleteAsync
CompleteAsync
方法时,我都会得到MessageLockLostException
这是我正在使用的包装类(相关部分):
public class ServiceBusClient
{
private readonly ServiceBusConnectionManager manager;
public ServiceBusClient(string connectionString)
{
manager = new ServiceBusConnectionManager(connectionString);
}
public async Task<Message> GetNextDownlinkMessage(string queueName)
{
var messageReceiver = new MessageReceiver(manager.Connection, queueName, ReceiveMode.PeekLock);
var message = await messageReceiver.ReceiveAsync();
await messageReceiver.CloseAsync();
return message;
}
public async Task Complete(string queueName, string lockToken)
{
var queueClient = new QueueClient(manager.Connection, queueName, ReceiveMode.PeekLock, null);
await queueClient.CompleteAsync(lockToken);
}
}
公共类ServiceBusClient
{
专用只读ServiceBusConnectionManager;
公共服务总线客户端(字符串连接字符串)
{
manager=新ServiceBusConnectionManager(connectionString);
}
公共异步任务GetNextDownlinkMessage(字符串queueName)
{
var messageReceiver=newmessagereceiver(manager.Connection、queueName、ReceiveMode.PeekLock);
var message=await messageReceiver.ReceiveAsync();
等待messageReceiver.CloseAsync();
返回消息;
}
公共异步任务完成(字符串queueName、字符串lockToken)
{
var queueClient=new queueClient(manager.Connection,queueName,ReceiveMode.PeekLock,null);
wait queueClient.CompleteAsync(lockToken);
}
}
我已经检查过,lockToken
实际上是在接收到的消息上设置的。我真的没有主意了
编辑:我后来意识到错误是因为我每次都实例化一个新的
MessageReceiver
对象,并且消息需要由用于获取消息的同一实例完成。我最终发现了问题。每次完成一条消息时,我都会创建一个新的QueueClient
实例。事实证明,您需要使用与接收消息完全相同的MessageReceiver
实例来完成或放弃消息。即使队列相同,也无法创建MessageReceiver
的新实例。听起来像是在使用旧版本的Service Bus SDK。有一个更新的版本将在本月底发布,供公众使用——你可以找到它
使用新库,您可以通过在SeviceBusReceiver
()上调用.CompleteMessageAsync(msg)
来完成消息:
字符串连接字符串=”;
字符串queueName=“”;
//由于ServiceBusClient实现了IAsyncDisposable,我们使用“wait using”创建它
等待使用var client=newservicebusclient(connectionString);
//创建一个接收器,我们可以使用它来接收和结算消息
ServiceBusReceiver receiver=客户端.CreateReceiver(队列名称);
//收到的消息是另一种类型,因为它包含一些服务集属性
ServiceBusReceivedMessage receivedMessage=Wait receiver.ReceiveMessageAsync();
//完成消息,从而将其从服务中删除
等待接收方。完成消息同步(receivedMessage);
最好提供指向存储库的链接,并简单复制此问题。这听起来很离谱。我在代码中添加了更多的上下文,并回答了我自己的问题。使用此新SDK,是否仍然需要使用相同的MessageReceiver
实例来完成消息,或者只要lockToken
正确,就可以创建新实例?对于延迟回复@Hannes Johansson表示歉意。您必须使用接收消息的接收器来完成消息。这是因为锁令牌由服务在消息发送到的实体的上下文中跟踪。在服务的眼中,每个ServiceBusReceiver都是一个新的实体。好的,谢谢您的解释。所以我的问题是我一直在创建新的ServiceBusReceivers。
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);
// create a receiver that we can use to receive and settle the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);
// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();
// complete the message, thereby deleting it from the service
await receiver.CompleteMessageAsync(receivedMessage);