[英]Azure Service Bus message lock not being renewed?
我建立了一項服務來支持Azure Service Bus中的多個隊列訂閱,但是出現了一些奇怪的現象。
我的訂閱單例類具有如下所示的方法:
public void Subscribe<TMessage>(Func<TMessage, Task> execution, int maxDop = 1, int ttl = 60) where TMessage : IServiceBusMessage
{
try
{
var messageLifespan = TimeSpan.FromSeconds(ttl);
var messageType = typeof(TMessage);
if (!_activeSubscriptionClients.TryGetValue(messageType, out var subscriptionClient))
{
subscriptionClient = _subscriptionClientFactory.Create(typeof(TMessage)).GetAwaiter().GetResult();
if (subscriptionClient.OperationTimeout < messageLifespan) subscriptionClient.OperationTimeout = messageLifespan;
if (subscriptionClient.ServiceBusConnection.OperationTimeout < messageLifespan)
subscriptionClient.ServiceBusConnection.OperationTimeout = messageLifespan;
_activeSubscriptionClients.AddOrUpdate(messageType, subscriptionClient, (key, value) => value);
}
var messageHandlerOptions = new MessageHandlerOptions(OnException)
{
MaxConcurrentCalls = maxDop,
AutoComplete = false,
MaxAutoRenewDuration = messageLifespan,
};
subscriptionClient.RegisterMessageHandler(
async (azureMessage, cancellationToken) =>
{
try
{
var textPayload = _encoding.GetString(azureMessage.Body);
var message = JsonConvert.DeserializeObject<TMessage>(textPayload);
if (message == null)
throw new FormatException($"Cannot deserialize the message payload to type '{typeof(TMessage).FullName}'.");
await execution.Invoke(message);
await subscriptionClient.CompleteAsync(azureMessage.SystemProperties.LockToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "ProcessMessagesAsync(Message, CancellationToken)");
await subscriptionClient.AbandonAsync(azureMessage.SystemProperties.LockToken);
}
}
, messageHandlerOptions);
}
catch (Exception ex)
{
_logger.LogError(ex, "Subscribe(Action<TMessage>)");
throw;
}
}
這個想法是,您為特定類型的消息訂閱Azure Service Bus,並且該消息直接對應於隊列。 在您的訂閱中,您傳遞了有關如何處理消息的委托。
這似乎奏效了。。。
無論我在長時間運行的任何給定消息上為MaxAutoRenewDuration
或OperationTimeout
設置ttl
MaxAutoRenewDuration
,一分鍾后都會將該消息從隊列中解鎖,然后另一個訂戶將其拾起並開始處理它。
我的理解是,這正是MaxAutoRenewDuration
應該防止的……但是似乎並沒有阻止任何東西。
誰能告訴我我需要做些什么來確保消費者擁有該信息直至完成?
我可以想到一些選項,您可能需要考慮一下。
而不是在SubscriptionClient中使用默認的ReceiveMode = PeekLock
,而是將其設置為ReceiveAndDelete,這樣,一旦使用了一條消息,它將被從隊列中刪除,並且不會被任何其他客戶端使用,這意味着您必須處理異常優雅地進行重試;
看看OperationTimeout
,根據doco的Duration after which individual operations will timeout
事實證明,使用者正在運行的遠程進程正在靜默失敗,並且未返回失敗狀態代碼(或其他任何信息); 自動刷新機制掛起等待結果,因此該消息最終超時。
我不清楚如何避免這種情況,但是一旦我在遠程進程上解決了該問題,該問題就不再可重現了。
故事的寓意:如果一切正常,但仍在超時,似乎自動刷新機制與您正在等待的異步操作共享了一些資源。 這可能是尋找失敗的另一個地方。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.