private async Task ProvisionQueueAsync(ServiceBus manager, string queueName) { if (!(await manager.QueueExistsAsync(queueName))) { _logger.LogDebug($"Provisioning queue: '{queueName}'"); // TODO :: Implement retry policies try { await manager.CreateQueueAsync(new QueueDescription(queueName) { AutoDeleteOnIdle = _options.AutoDeleteOnIdle, DefaultMessageTimeToLive = _options.MessageTimeToLive, EnableBatchedOperations = _options.EnableServerSideBatchedOperations, EnableExpress = _options.EnableExpress, EnablePartitioning = _options.EnablePartitioning, LockDuration = _options.MessageLockDuration, MaxDeliveryCount = _options.MaximumDeliveryCount }); _logger.LogInformation($"Provisioned queue: '{queueName}'"); } catch (Exception ex) { _logger.LogError($"An error occured whilst provisioning queue: '{queueName}'", ex); } } else { _logger.LogDebug($"Queue '{queueName}' already exists, no need to provision."); } RemoveOperation(queueName); }
private async Task ProvisionTopicAsync(ServiceBus manager, string topicName, bool keepOperationPending = false) { if (!(await manager.TopicExistsAsync(topicName))) { _logger.LogDebug($"Provisioning topic: '{topicName}'"); // TODO :: Implement retry policies try { await manager.CreateTopicAsync(new TopicDescription(topicName) { AutoDeleteOnIdle = _options.AutoDeleteOnIdle, DefaultMessageTimeToLive = _options.MessageTimeToLive, EnableBatchedOperations = _options.EnableServerSideBatchedOperations, EnableExpress = _options.EnableExpress, EnablePartitioning = _options.EnablePartitioning }); _logger.LogInformation($"Provisioned topic: '{topicName}'"); } catch (Exception ex) { _logger.LogError($"An error occured whilst provisioning topic: '{topicName}'", ex); } } else { _logger.LogDebug($"Topic '{topicName}' already exists, no need to provision."); } if (!keepOperationPending) { RemoveOperation(topicName); } }
private ServiceBus CreateServiceBusManager() { var manager = ServiceBus.CreateFromConnectionString(_options.ConnectionString); manager.Settings.OperationTimeout = _options.RemoteOperationTimeout; return(manager); }
/// <summary> /// Checks if a topic by the provided <paramref name="topicName"/> exists and /// Checks if a subscription name by the provided <paramref name="subscriptionName"/> exists. /// </summary> protected virtual void CheckTopicExists(Manager manager, string topicName, string subscriptionName) { // Configure Queue Settings var eventTopicDescription = new TopicDescription(topicName) { #if NET452 MaxSizeInMegabytes = 5120, #endif #if NETSTANDARD2_0 MaxSizeInMB = 5120, #endif DefaultMessageTimeToLive = new TimeSpan(0, 25, 0), EnablePartitioning = true, EnableBatchedOperations = true, }; #if NETSTANDARD2_0 Task <bool> checkTask = manager.TopicExistsAsync(topicName); checkTask.Wait(1500); if (!checkTask.Result) { Task <TopicDescription> createTopicTask = manager.CreateTopicAsync(eventTopicDescription); createTopicTask.Wait(1500); } checkTask = manager.SubscriptionExistsAsync(topicName, subscriptionName); checkTask.Wait(1500); if (!checkTask.Result) { var subscriptionDescription = new SubscriptionDescription(topicName, subscriptionName) { DefaultMessageTimeToLive = eventTopicDescription.DefaultMessageTimeToLive, EnableBatchedOperations = eventTopicDescription.EnableBatchedOperations, }; Task <SubscriptionDescription> createTask = manager.CreateSubscriptionAsync(subscriptionDescription); createTask.Wait(1500); } #endif #if NET452 // Create the topic if it does not exist already if (!manager.TopicExists(eventTopicDescription.Path)) { manager.CreateTopic(eventTopicDescription); } if (!manager.SubscriptionExists(eventTopicDescription.Path, subscriptionName)) { manager.CreateSubscription ( new SubscriptionDescription(eventTopicDescription.Path, subscriptionName) { DefaultMessageTimeToLive = new TimeSpan(0, 25, 0), EnableBatchedOperations = true, EnableDeadLetteringOnFilterEvaluationExceptions = true } ); } #endif }
private async Task ProvisionSubscriptionAsync(ServiceBus manager, string topicName, string subscriptionName) { await ProvisionTopicAsync(manager, topicName, true); if (!(await manager.SubscriptionExistsAsync(topicName, subscriptionName))) { _logger.LogDebug($"Provisioning subscription: '{topicName}/{subscriptionName}'"); // TODO :: Implement retry policies try { await manager.CreateSubscriptionAsync(new SubscriptionDescription(topicName, subscriptionName) { AutoDeleteOnIdle = _options.AutoDeleteOnIdle, DefaultMessageTimeToLive = _options.MessageTimeToLive, EnableBatchedOperations = _options.EnableServerSideBatchedOperations, LockDuration = _options.MessageLockDuration, MaxDeliveryCount = _options.MaximumDeliveryCount }); _logger.LogInformation($"Provisioned subscription: '{topicName}/{subscriptionName}'"); } catch (Exception ex) { _logger.LogError($"An error occured whilst provisioning subscription: '{topicName}/{subscriptionName}'", ex); } } else { _logger.LogDebug($"Subscription '{topicName}/{subscriptionName}' already exists, no need to provision."); } RemoveOperation(topicName); }
/// <summary> /// Creates <see cref="AzureBus{TAuthenticationToken}.NumberOfReceiversCount"/> <see cref="IMessageReceiver"/>. /// If flushing is required, any flushed <see cref="IMessageReceiver"/> has <see cref="ClientEntity.Close()"/> called on it first. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> /// <param name="serviceBusReceivers">The receivers collection to place <see cref="IMessageReceiver"/> instances into.</param> /// <param name="topicName">The topic name.</param> /// <param name="topicSubscriptionName">The topic subscription name.</param> #endif #if NETSTANDARD2_0 /// <summary> /// Creates <see cref="AzureBus{TAuthenticationToken}.NumberOfReceiversCount"/> <see cref="IMessageReceiver"/>. /// If flushing is required, any flushed <see cref="IMessageReceiver"/> has <see cref="ClientEntity.CloseAsync()"/> called on it first. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> /// <param name="serviceBusReceivers">The receivers collection to place <see cref="IMessageReceiver"/> instances into.</param> /// <param name="topicName">The topic name.</param> /// <param name="topicSubscriptionName">The topic subscription name.</param> #endif protected virtual void InstantiateReceiving(Manager manager, IDictionary <int, IMessageReceiver> serviceBusReceivers, string topicName, string topicSubscriptionName) { for (int i = 0; i < NumberOfReceiversCount; i++) { #if NET452 IMessageReceiver serviceBusReceiver = SubscriptionClient.CreateFromConnectionString(ConnectionString, topicName, topicSubscriptionName); #endif #if NETSTANDARD2_0 IMessageReceiver serviceBusReceiver = new MessageReceiver(ConnectionString, EntityNameHelper.FormatSubscriptionPath(topicName, topicSubscriptionName)); #endif if (serviceBusReceivers.ContainsKey(i)) { serviceBusReceivers[i] = serviceBusReceiver; } else { serviceBusReceivers.Add(i, serviceBusReceiver); } } // Remove any if the number has decreased for (int i = NumberOfReceiversCount; i < serviceBusReceivers.Count; i++) { IMessageReceiver serviceBusReceiver; if (serviceBusReceivers.TryGetValue(i, out serviceBusReceiver)) { #if NET452 serviceBusReceiver.Close(); #endif #if NETSTANDARD2_0 serviceBusReceiver.CloseAsync().Wait(1500); #endif } serviceBusReceivers.Remove(i); } }
/// <summary> /// Instantiate receiving on this bus by /// calling <see cref="CheckPrivateTopicExists"/> and <see cref="CheckPublicTopicExists"/> /// then InstantiateReceiving for private and public topics, /// calls <see cref="CleanUpDeadLetters"/> for the private and public topics, /// then calling <see cref="AzureBus{TAuthenticationToken}.StartSettingsChecking"/> /// </summary> protected override void InstantiateReceiving() { #if NET452 Manager manager = Manager.CreateFromConnectionString(ConnectionString); #endif #if NETSTANDARD2_0 var manager = new Manager(ConnectionString); #endif CheckPrivateTopicExists(manager); CheckPublicTopicExists(manager); try { InstantiateReceiving(manager, PrivateServiceBusReceivers, PrivateTopicName, PrivateTopicSubscriptionName); } catch (UriFormatException exception) { throw new InvalidConfigurationException("The connection string for one of the private Service Bus receivers may be invalid.", exception); } try { InstantiateReceiving(manager, PublicServiceBusReceivers, PublicTopicName, PublicTopicSubscriptionName); } catch (UriFormatException exception) { throw new InvalidConfigurationException("The connection string for one of the public Service Bus receivers may be invalid.", exception); } bool enableDeadLetterCleanUp; string enableDeadLetterCleanUpValue = ConfigurationManager.GetSetting("Cqrs.Azure.Servicebus.EnableDeadLetterCleanUp"); if (bool.TryParse(enableDeadLetterCleanUpValue, out enableDeadLetterCleanUp) && enableDeadLetterCleanUp) { CleanUpDeadLetters(PrivateTopicName, PrivateTopicSubscriptionName); CleanUpDeadLetters(PublicTopicName, PublicTopicSubscriptionName); } // If this is also a publisher, then it will the check over there and that will handle this // we only need to check one of these if (PublicServiceBusPublisher != null) { return; } StartSettingsChecking(); }
/// <summary> /// Instantiate publishing on this bus by /// calling <see cref="CheckPrivateTopicExists"/> and <see cref="CheckPublicTopicExists"/> /// then calling <see cref="AzureBus{TAuthenticationToken}.StartSettingsChecking"/> /// </summary> protected override void InstantiatePublishing() { #if NET452 Manager manager = Manager.CreateFromConnectionString(ConnectionString); #endif #if NETSTANDARD2_0 var manager = new Manager(ConnectionString); #endif CheckPrivateTopicExists(manager); CheckPublicTopicExists(manager); #if NET452 PrivateServiceBusPublisher = TopicClient.CreateFromConnectionString(ConnectionString, PrivateTopicName); PublicServiceBusPublisher = TopicClient.CreateFromConnectionString(ConnectionString, PublicTopicName); #endif #if NETSTANDARD2_0 PrivateServiceBusPublisher = new TopicClient(ConnectionString, PrivateTopicName); PublicServiceBusPublisher = new TopicClient(ConnectionString, PublicTopicName); #endif StartSettingsChecking(); }
/// <summary> /// Instantiate receiving on this bus by /// calling <see cref="CheckPrivateHubExists"/> and <see cref="CheckPublicHubExists"/> /// then InstantiateReceiving for private and public topics, /// then calling <see cref="AzureBus{TAuthenticationToken}.StartSettingsChecking"/> /// </summary> protected override void InstantiateReceiving() { #if NET452 Manager manager = Manager.CreateFromConnectionString(ConnectionString); #endif #if NETSTANDARD2_0 var manager = new Manager(ConnectionString); #endif CheckPrivateHubExists(manager); CheckPublicHubExists(manager); EventHubReceiver = new EventProcessorHost(PublicEventHubName, PublicEventHubConsumerGroupName, ConnectionString, StorageConnectionString, "Cqrs"); // If this is also a publisher, then it will the check over there and that will handle this if (EventHubPublisher != null) { return; } StartSettingsChecking(); }
/// <summary> /// Checks if a event hub by the provided <paramref name="hubName"/> exists and /// Checks if a consumer group by the provided <paramref name="consumerGroupNames"/> exists. /// </summary> protected virtual void CheckHubExists(Manager manager, string hubName, string consumerGroupNames) { #if NET452 // Configure Queue Settings var eventHubDescription = new EventHubDescription(hubName) { MessageRetentionInDays = long.MaxValue, }; // Create the topic if it does not exist already manager.CreateEventHubIfNotExists(eventHubDescription); var subscriptionDescription = new SubscriptionDescription(eventHubDescription.Path, consumerGroupNames); if (!manager.SubscriptionExists(eventHubDescription.Path, consumerGroupNames)) { manager.CreateSubscription(subscriptionDescription); } #endif #if NETSTANDARD2_0 /* * // Configure Queue Settings * var eventHubDescription = new EventHubDescription(hubName) * { * MessageRetentionInDays = long.MaxValue, * }; * * // Create the topic if it does not exist already * manager.CreateEventHubIfNotExists(eventHubDescription); * * Task<bool> checkTask = manager.SubscriptionExistsAsync(eventHubDescription.Path, consumerGroupNames); * checkTask.Wait(1500); * if (!checkTask.Result) * manager.CreateSubscriptionAsync(subscriptionDescription).Wait(1500); */ Logger.LogWarning($"Checking EventHubs and subscriptions is not currently implemented until the Azure libraries provide management facilities. You will need to check these objects exist manually: EventHub {hubName}, Subscription/Consumer Group {consumerGroupNames}", "AzureEventHub"); #endif }
/// <summary> /// Instantiate publishing on this bus by /// calling <see cref="CheckPrivateHubExists"/> and <see cref="CheckPublicHubExists"/> /// then calling <see cref="AzureBus{TAuthenticationToken}.StartSettingsChecking"/> /// </summary> protected override void InstantiatePublishing() { #if NET452 Manager manager = Manager.CreateFromConnectionString(ConnectionString); #endif #if NETSTANDARD2_0 var manager = new Manager(ConnectionString); #endif CheckPrivateHubExists(manager); CheckPublicHubExists(manager); #if NET452 EventHubPublisher = EventHubClient.CreateFromConnectionString(ConnectionString, PublicEventHubName); #endif #if NETSTANDARD2_0 var connectionStringBuilder = new EventHubsConnectionStringBuilder(ConnectionString) { EntityPath = PublicEventHubName }; EventHubPublisher = EventHubClient.Create(connectionStringBuilder); #endif StartSettingsChecking(); }
/// <summary> /// Calls <see cref="AzureServiceBus{TAuthenticationToken}.InstantiateReceiving()"/> /// then uses a <see cref="Task"/> to apply the <see cref="FilterKey"/> as a <see cref="RuleDescription"/> /// to the <see cref="IMessageReceiver"/> instances in <paramref name="serviceBusReceivers"/>. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> /// <param name="serviceBusReceivers">The receivers collection to place <see cref="IMessageReceiver"/> instances into.</param> /// <param name="topicName">The topic name.</param> /// <param name="topicSubscriptionName">The topic subscription name.</param> protected override void InstantiateReceiving(Manager manager, IDictionary <int, IMessageReceiver> serviceBusReceivers, string topicName, string topicSubscriptionName) { base.InstantiateReceiving(manager, serviceBusReceivers, topicName, topicSubscriptionName); Task.Factory.StartNewSafely (() => { // Because refreshing the rule can take a while, we only want to do this when the value changes string filter; if (!ConfigurationManager.TryGetSetting(FilterKeyConfigurationKey, out filter)) { return; } if (FilterKey.ContainsKey(topicName) && FilterKey[topicName] == filter) { return; } FilterKey[topicName] = filter; // https://docs.microsoft.com/en-us/azure/application-insights/app-insights-analytics-reference#summarize-operator // http://www.summa.com/blog/business-blog/everything-you-need-to-know-about-azure-service-bus-brokered-messaging-part-2#rulesfiltersactions // https://github.com/Azure-Samples/azure-servicebus-messaging-samples/tree/master/TopicFilters #if NET452 SubscriptionClient client = serviceBusReceivers[0]; #endif #if NETSTANDARD2_0 // Since the IMessageReceiver and it's concrete implementation doesn't allow for the management of rules, we're creating a SubscriptionClient just to do the rules... it gets cleaned up somewhat below. SubscriptionClient client = new SubscriptionClient(ConnectionString, topicName, topicSubscriptionName); #endif bool reAddRule = false; try { #if NET452 IEnumerable <RuleDescription> rules = manager.GetRules(client.TopicPath, client.Name).ToList(); #endif #if NETSTANDARD2_0 Task <IList <RuleDescription> > getRulesTask = manager.GetRulesAsync(client.TopicPath, client.SubscriptionName); getRulesTask.Wait(); IEnumerable <RuleDescription> rules = getRulesTask.Result; #endif RuleDescription ruleDescription = rules.SingleOrDefault(rule => rule.Name == "CqrsConfiguredFilter"); if (ruleDescription != null) { var sqlFilter = ruleDescription.Filter as SqlFilter; if (sqlFilter == null && !string.IsNullOrWhiteSpace(filter)) { reAddRule = true; } else if (sqlFilter != null && sqlFilter.SqlExpression != filter) { reAddRule = true; } if (sqlFilter != null && reAddRule) { #if NET452 client.RemoveRule("CqrsConfiguredFilter"); #endif #if NETSTANDARD2_0 client.RemoveRuleAsync("CqrsConfiguredFilter").Wait(); #endif } } else if (!string.IsNullOrWhiteSpace(filter)) { reAddRule = true; } ruleDescription = rules.SingleOrDefault(rule => rule.Name == "$Default"); // If there is a default rule and we have a rule, it will cause issues if (!string.IsNullOrWhiteSpace(filter) && ruleDescription != null) { #if NET452 client.RemoveRule("$Default"); #endif #if NETSTANDARD2_0 client.RemoveRuleAsync("$Default").Wait(); #endif } // If we don't have a rule and there is no longer a default rule, it will cause issues else if (string.IsNullOrWhiteSpace(filter) && !rules.Any()) { ruleDescription = new RuleDescription ( "$Default", new SqlFilter("1=1") ); #if NET452 client.AddRule(ruleDescription); #endif #if NETSTANDARD2_0 client.AddRuleAsync(ruleDescription).Wait(); #endif } } catch (AggregateException ex) { if (!(ex.InnerException is MessagingEntityNotFoundException)) { throw; } } catch (MessagingEntityNotFoundException) { } if (!reAddRule) { return; } int loopCounter = 0; while (loopCounter < 10) { try { RuleDescription ruleDescription = new RuleDescription ( "CqrsConfiguredFilter", new SqlFilter(filter) ); #if NET452 client.AddRule(ruleDescription); #endif #if NETSTANDARD2_0 client.AddRuleAsync(ruleDescription).Wait(); #endif break; } catch (MessagingEntityAlreadyExistsException exception) { loopCounter++; // Still waiting for the delete to complete Thread.Sleep(1000); if (loopCounter == 9) { Logger.LogError("Setting the filter failed as it already exists.", exception: exception); TelemetryHelper.TrackException(exception); } } catch (Exception exception) { Logger.LogError("Setting the filter failed.", exception: exception); TelemetryHelper.TrackException(exception); break; } } #if NETSTANDARD2_0 client.CloseAsync(); #endif }); }
/// <summary> /// Checks if the public topic and subscription name exists as per <see cref="PublicTopicName"/> and <see cref="PublicTopicSubscriptionName"/>. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> protected virtual void CheckPublicTopicExists(Manager manager) { CheckTopicExists(manager, PublicTopicName = ConfigurationManager.GetSetting(PublicTopicNameConfigurationKey) ?? DefaultPublicTopicName, PublicTopicSubscriptionName = ConfigurationManager.GetSetting(PublicTopicSubscriptionNameConfigurationKey) ?? DefaultPublicTopicSubscriptionName); }
/// <summary> /// Checks if the public hub and consumer group name exists as per <see cref="PublicEventHubName"/> and <see cref="PublicEventHubConsumerGroupName"/>. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> protected virtual void CheckPublicHubExists(Manager manager) { CheckHubExists(manager, PublicEventHubName = ConfigurationManager.GetSetting(PublicEventHubNameConfigurationKey) ?? DefaultPublicEventHubName, PublicEventHubConsumerGroupName = ConfigurationManager.GetSetting(PublicEventHubConsumerGroupNameConfigurationKey) ?? DefaultPublicEventHubConsumerGroupName); }
/// <summary> /// Checks if the public topic and subscription name exists as per <see cref="PublicTopicName"/> and <see cref="PublicTopicSubscriptionName"/>. /// </summary> /// <param name="manager">The <see cref="Manager"/>.</param> /// <param name="createSubscriptionIfNotExists">Create a subscription if there isn't one</param> protected virtual void CheckPublicTopicExists(Manager manager, bool createSubscriptionIfNotExists = true) { CheckTopicExists(manager, PublicTopicName = ConfigurationManager.GetSetting(PublicTopicNameConfigurationKey) ?? DefaultPublicTopicName, PublicTopicSubscriptionName = ConfigurationManager.GetSetting(PublicTopicSubscriptionNameConfigurationKey) ?? DefaultPublicTopicSubscriptionName, createSubscriptionIfNotExists); }