我在使用Azure Service Bus实例时遇到了一个非常令人沮丧的问题。具体来说,我有一个名为"命令"经过一段时间后,它将停止正确地将消息代理到其订阅。我观察到以下行为让我处于目前困惑状态:
这只会在主题存在一段时间后才会发生,通常是一夜之间。一切都将在晚上工作,但是当我早上回来时,主题已经停止运作,唯一的解决方案似乎是删除并重新创建它。
如下图所示,主题似乎正在接收消息,因为我在发送后没有收到任何例外,并且"有效消息计数" "字节大小"关于该主题的属性确实增加。它只是不会将消息发送到订阅:
我认为也许我的订阅中的过滤器搞砸了,所以为了测试这个,我删除了这些订阅,并使用默认过滤器通过资源管理器创建了一个新订阅。完成此操作后,我通过该主题发送了一些新消息,但新订阅仍未收到这些消息。
我在服务总线上运行了其他主题(例如"事件"在上图中),但他们似乎没有表现出相同的行为。它们以相同的方式配置,但运行得很好。
我对任何可能导致这种奇怪行为的理论持开放态度。如果有助于解决此问题,我很乐意提供其他信息。
代码块:
创建主题:
private async Task<bool> CreateTopicAsync(NamespaceManager namespaceManager, string topicName, CancellationToken cancel, TimeSpan maxWaitTime)
{
var retVal = false;
var maxTimeToCreateTopic = DateTime.UtcNow + maxWaitTime;
while (!cancel.IsCancellationRequested && DateTime.UtcNow < maxTimeToCreateTopic)
{
try
{
await namespaceManager.CreateTopicAsync(new TopicDescription(topicName)
{
EnableBatchedOperations = true,
EnableFilteringMessagesBeforePublishing = true
});
retVal = true;
break;
}
catch (Exception ex)
{
LogError("Exception thrown when creating topic: {0}", ex);
}
if (!retVal)
{
LogWarning("Topic still does not exist, pausing and then retrying creation.");
await Task.Delay(_delayMs);
}
}
return retVal;
}
创建订阅:
private async Task<bool> CreateSubscriptionAsync(NamespaceManager namespaceManager, string topicName, string subscriptionName, string filter, CancellationToken cancel, TimeSpan maxWaitTime)
{
var retVal = false;
var maxTimeToCreateSubscription = DateTime.UtcNow + maxWaitTime;
while (!cancel.IsCancellationRequested && DateTime.UtcNow < maxTimeToCreateSubscription)
{
try
{
if (string.IsNullOrEmpty(filter))
{
namespaceManager.CreateSubscription(topicName, subscriptionName);
}
else
{
namespaceManager.CreateSubscription(topicName, subscriptionName, new SqlFilter(filter));
}
retVal = true;
break;
}
catch (Exception ex)
{
LogError("Exception thrown when creating subscription: {0}", ex);
}
LogWarning("Subscription still does not exist, pausing and then retrying creation.");
await Task.Delay(_delayMs);
}
return retVal;
}
发送消息至主题:
BrokeredMessage brokeredMessage = null;
try
{
var type = nextMessage.GetType().AssemblyQualifiedName;
var jsonString = JsonConvert.SerializeObject(nextMessage);
var jsonStream = jsonString.ToStream();
brokeredMessage = new BrokeredMessage(jsonStream, true);
brokeredMessage.Properties["__messageType__"] = type;
if (nextData.Properties != null && nextData.Properties.Count > 0)
{
foreach (var prop in nextData.Properties)
{
brokeredMessage.Properties.Add(prop.Key, prop.Value);
}
}
}
catch (Exception ex)
{
LogError("Exception thrown when creating brokered message: {0}", ex);
brokeredMessage = null;
}
if (brokeredMessage != null)
{
var messageSentSuccessfully = false;
try
{
await client.SendAsync(brokeredMessage);
numConsecutiveFailures = 0;
messageSentSuccessfully = true;
}
catch (Exception ex)
{
numConsecutiveFailures++;
LogError("Exception thrown from SendAsync: {0}. Fail count is {1}.", ex, numConsecutiveFailures);
await Task.Delay(_delayMs);
}
}
主题客户端中的传递仅使用TopicClient.CreateFromConnectionString方法创建。
从订阅接收消息:
private async Task ReceiveLoopAsync(SubscriptionClient client, CancellationToken cancel, TimeSpan maxReceiveWaitTime)
{
var numConsecutiveFailures = 0;
var maxConsecutiveFailures = 5;
while (!cancel.IsCancellationRequested && numConsecutiveFailures < maxConsecutiveFailures)
{
BrokeredMessage newMsg = null;
try
{
newMsg = await client.ReceiveAsync(maxReceiveWaitTime);
numConsecutiveFailures = 0;
}
catch (Exception ex)
{
numConsecutiveFailures++;
LogError("Exception thrown from ReceiveAsync: {0}. Fail count is {1}.", ex, numConsecutiveFailures);
await Task.Delay(_delayMs);
}
// newMsg will be null if there were no messages to process after the allotted timeout expired.
if (newMsg != null)
{
// Just a function call.
_onMessageReceived?.Invoke(newMsg);
}
//LogDebug("Bottom of Receive");
}
//LogDebug("Exit Receive");
}
订阅客户端中的传递仅使用SubscriptionClient.CreateFromConnectionString方法创建。