【问题标题】:Azure Service Bus keeps throwing MessageLockLostExceptionsAzure 服务总线不断抛出 MessageLockLostException
【发布时间】:2018-12-12 17:11:09
【问题描述】:

我在处理消息时不断收到MessageLockLostExceptions

现在我想通过添加Task.Delay(10_000) 来模拟一个运行时间稍长的消息处理任务(但仍然在LockDuration 范围内)。但是我每收到 4 条消息就会收到一个 MessageLockLostException

即使我设置了MaxAutoRenewDuration = TimeSpan.FromDays(30)PrefetchCount = 0,也会发生这种情况。


这是消息处理方式,我稍微改了一下,打印出剩余的锁时长:

    private static async Task processMessagesAsync(Message message, CancellationToken token)
    {
        Console.Write($"Received message: {message.SystemProperties.SequenceNumber}. Remaining lock duration: {message.SystemProperties.LockedUntilUtc - DateTime.UtcNow}");
        await Task.Delay(10000);
        await queueClient.CompleteAsync(message.SystemProperties.LockToken);
        Console.WriteLine(" - Complete!");
    }

样本输出:

======================================================
Press ENTER key to exit after receiving all the messages.
======================================================
Received message: 3659174697238584. Remaining lock duration: 00:00:30.8269132 - Complete!
Received message: 19421773393035331. Remaining lock duration: 00:00:20.5271654 - Complete!
Received message: 11540474045136941. Remaining lock duration: 00:00:10.3372697 - Complete!
Received message: 15762598695796784. Remaining lock duration: 00:00:00.1776760
Message handler encountered an exception     Microsoft.Azure.ServiceBus.MessageLockLostException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue. Reference:2c6caac3-e607-4130-a522-f75e4636e130, TrackingId:3ff82738-664d-4aca-b55f-ba3900f1c640_B17, SystemTracker:ocgtesting:queue:workflow~63, Timestamp:2018-12-12T17:01:59
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.OnRenewLockAsync(String lockToken) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\Core\MessageReceiver.cs:line 1260
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.<>c__DisplayClass74_0.<<RenewLockAsync>b__0>d.MoveNext() in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\Core\MessageReceiver.cs:line 771
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Azure.ServiceBus.RetryPolicy.RunOperation(Func`1 operation, TimeSpan operationTimeout) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\RetryPolicy.cs:line 83
at Microsoft.Azure.ServiceBus.RetryPolicy.RunOperation(Func`1 operation, TimeSpan operationTimeout) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\RetryPolicy.cs:line 105
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.RenewLockAsync(String lockToken) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\Core\MessageReceiver.cs:line 773
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.RenewLockAsync(Message message) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\Core\MessageReceiver.cs:line 742
at Microsoft.Azure.ServiceBus.MessageReceivePump.RenewMessageLockTask(Message message, CancellationToken renewLockCancellationToken) in C:\source\azure-service-bus-dotnet\src\Microsoft.Azure.ServiceBus\MessageReceivePump.cs:line 248.

完整代码在这里:https://pastebin.com/sFGBgE0s

【问题讨论】:

  • 您如何收到您的消息?你能分享一个完整的repro吗?您收到剩余锁定持续时间少于MaxLockDuration 的消息这一事实清楚地表明某些事情已经关闭。
  • @SeanFeldman 是的,这里:pastebin.com/sFGBgE0s
  • pastebin中的代码使用了Thread.Sleep而不是TaskDelay,并且PrefetchCount=0已经被注释掉了,但是没有什么区别。
  • 您使用的是什么版本的 ASB 客户端?
  • 我怀疑这是一个错误。看我的回答below

标签: c# azureservicebus azure-servicebus-queues


【解决方案1】:

复制品中缺少的一件事是队列描述。请务必注意这些细节,因为您遇到的问题与客户端无关,很可能与代理或底层 AMQP 库有关。

对于非分区队列,此设置工作正常。它不适用于分区队列(标准层)。新老客户都可以观察到。我已经提出了一个与代理相关的issue,供 Azure 服务总线团队进行调查。

【讨论】:

  • 我也看到了这个问题
  • 这是一个代理约束。
【解决方案2】:

您需要在Lock Token 过期之前Complete 消息。 Lock Token 过期后,您将在整个操作过程中收到MessageLockLostException

我可以看到您将每条消息的线程执行延迟 10 秒。但是消息似乎是在同一时间获取的,这就是为什么每条消息的剩余锁定持续时间不断减少的原因。

对于第四条消息,剩余锁定持续时间为00:00:00.1776760。所以,在177 milliseconds 之后,锁就会过期。您在下一行将线程延迟10 seconds。所以,锁会过期,你会得到MessageLockLostException。为避免此异常,请删除 Delay

【讨论】:

  • 我故意添加了延迟来模拟运行时间更长的任务 - 但比 LockDuration 更短。问题是为什么剩余的锁定持续时间不断减少。
  • 消息将被 processMessagesAsync 连续接收。假设你有 10 条消息,不管你在 processMessagesAsync 中有什么,所有的消息都会被一一接收。因此 10 条消息将排队等待延迟,从而导致锁定令牌到期。请注意:消息检索不会等待 processMessagesAsync 完成执行,消息会堆积起来等待延迟。
  • 观察到的行为确实符合您的解释。但这将是一个错误,不是吗?我设置了 PrefetchCount = 0,这应该禁用预取(参见 docs.microsoft.com/en-us/azure/service-bus-messaging/…)。必须有办法禁用预取,否则无法避免锁过期。
  • 这不是错误。这是预期的行为。预取仅在后台获取消息,并在临时内存的帮助下使其可供接收方更快地处理。在您的情况下,如果您使用 RegisterMessageHandler(),它不会像 While 循环那样工作,它会获取消息并异步启动 ProcessMessageAsync()。如果您希望仅在任务完成后接收下一条消息,则应在 while 循环中使用 ReceiveAsync()。
  • @Arunprabhu 在消息接收器上的预取默认为零。 MoB 明确将其设置为零。他的设置是有效的,如果为了简单起见,他想使用消息处理程序 API 进行串行处理,那绝对没问题。我怀疑这是一个错误。看我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多