C# 未超过锁定持续时间时,Azure服务总线为非分区队列抛出MessageLockLostException

C# 未超过锁定持续时间时,Azure服务总线为非分区队列抛出MessageLockLostException,c#,azure,azureservicebus,C#,Azure,Azureservicebus,我正在尝试使用PeekLockreceive模式接收消息,处理消息(处理时间远低于消息锁定持续时间),然后完成消息。我已经检查了周围是否有类似的问题,但我想我已经排除了所有建议的解决方案 队列未分区 当我进行测试时,队列上只有一条消息,我甚至尝试将PrefetchCount设置为1 只有一个接收器处于活动状态 我已将锁定持续时间增加到5分钟,处理时间约为20秒。检查收到的消息时,我可以看到LockedUntil属性比CompleteAsync调用晚得多 即便如此,每次调用CompleteAs

我正在尝试使用
PeekLock
receive模式接收消息,处理消息(处理时间远低于消息锁定持续时间),然后完成消息。我已经检查了周围是否有类似的问题,但我想我已经排除了所有建议的解决方案

  • 队列未分区
  • 当我进行测试时,队列上只有一条消息,我甚至尝试将
    PrefetchCount
    设置为1
  • 只有一个接收器处于活动状态
  • 我已将
    锁定持续时间增加到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);