public Task DeleteSubscription(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo) { if (metadata is ForwardingTopologySubscriptionMetadata) { return(azureServiceBusForwardingSubscriptionCreator.DeleteSubscription(topicPath, subscriptionName, metadata, sqlFilter, namespaceManager, forwardTo)); } return(azureServiceBusSubscriptionCreatorV6.DeleteSubscription(topicPath, subscriptionName, metadata, sqlFilter, namespaceManager, forwardTo)); }
public async Task <SubscriptionDescription> Create(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo = null) { var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName) { EnableBatchedOperations = subscriptionSettings.EnableBatchedOperations, AutoDeleteOnIdle = subscriptionSettings.AutoDeleteOnIdle, DefaultMessageTimeToLive = subscriptionSettings.DefaultMessageTimeToLive, EnableDeadLetteringOnFilterEvaluationExceptions = subscriptionSettings.EnableDeadLetteringOnFilterEvaluationExceptions, EnableDeadLetteringOnMessageExpiration = subscriptionSettings.EnableDeadLetteringOnMessageExpiration, LockDuration = subscriptionSettings.LockDuration, MaxDeliveryCount = DefaultMaxDeliveryCountForNoImmediateRetries }; if (subscriptionSettings.ForwardDeadLetteredMessagesToCondition(SubscriptionClient.FormatSubscriptionPath(topicPath, subscriptionName))) { subscriptionDescription.ForwardDeadLetteredMessagesTo = subscriptionSettings.ForwardDeadLetteredMessagesTo; } subscriptionSettings.DescriptionCustomizer(subscriptionDescription); if (!string.IsNullOrWhiteSpace(forwardTo)) { subscriptionDescription.ForwardTo = forwardTo; } subscriptionDescription.UserMetadata = metadata.Description; try { if (!await ExistsAsync(topicPath, subscriptionName, metadata.Description, namespaceManager).ConfigureAwait(false)) { await namespaceManager.CreateSubscription(subscriptionDescription, sqlFilter).ConfigureAwait(false); logger.Info($"Subscription '{subscriptionDescription.UserMetadata}' in namespace '{namespaceManager.Address.Host}' created as '{subscriptionDescription.Name}'."); var key = GenerateSubscriptionKey(namespaceManager.Address, subscriptionDescription.TopicPath, subscriptionDescription.Name); await rememberExistence.AddOrUpdate(key, keyNotFound => TaskEx.CompletedTrue, (updateTopicPath, previousValue) => TaskEx.CompletedTrue).ConfigureAwait(false); } else { logger.Info($"Subscription '{subscriptionDescription.Name}' in namespace '{namespaceManager.Address.Host}' aka '{subscriptionDescription.UserMetadata}' already exists, skipping creation."); logger.InfoFormat("Checking if subscription '{0}' in namespace '{1}' needs to be updated.", subscriptionDescription.Name, namespaceManager.Address.Host); var existingSubscriptionDescription = await namespaceManager.GetSubscription(subscriptionDescription.TopicPath, subscriptionDescription.Name).ConfigureAwait(false); if (MembersAreNotEqual(existingSubscriptionDescription, subscriptionDescription)) { OverrideImmutableMembers(existingSubscriptionDescription, subscriptionDescription); logger.InfoFormat("Updating subscription '{0}' in namespace '{1}' with new description.", subscriptionDescription.Name, namespaceManager.Address.Host); await namespaceManager.UpdateSubscription(subscriptionDescription).ConfigureAwait(false); } } } catch (MessagingEntityAlreadyExistsException) { // the subscription already exists or another node beat us to it, which is ok logger.InfoFormat("Subscription '{0}' in namespace '{1}' already exists, another node probably beat us to it.", subscriptionDescription.Name, namespaceManager.Address.Host); } catch (TimeoutException) { logger.InfoFormat("Timeout occurred on subscription creation for topic '{0}' subscription name '{1}' in namespace '{2}' going to validate if it doesn't exist.", subscriptionDescription.TopicPath, subscriptionDescription.Name, namespaceManager.Address.Host); // there is a chance that the timeout occurred, but the topic was still created, check again if (!await ExistsAsync(subscriptionDescription.TopicPath, subscriptionDescription.Name, metadata.Description, namespaceManager, removeCacheEntry: true).ConfigureAwait(false)) { throw; } logger.InfoFormat("Looks like subscription '{0}' in namespace '{1}' exists anyway.", subscriptionDescription.Name, namespaceManager.Address.Host); } catch (MessagingException ex) { var loggedMessage = $"{(ex.IsTransient ? "Transient" : "Non transient")} {ex.GetType().Name} occurred on subscription '{subscriptionDescription.Name}' creation for topic '{subscriptionDescription.TopicPath}' in namespace '{namespaceManager.Address.Host}'."; if (!ex.IsTransient) { logger.Fatal(loggedMessage, ex); throw; } logger.Info(loggedMessage, ex); } return(subscriptionDescription); }
public async Task DeleteSubscription(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo) { var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName); try { if (await ExistsAsync(topicPath, subscriptionName, metadata.Description, namespaceManager, true).ConfigureAwait(false)) { await namespaceManager.DeleteSubscription(subscriptionDescription).ConfigureAwait(false); } } catch (MessagingException ex) { var loggedMessage = $"{(ex.IsTransient ? "Transient" : "Non transient")} {ex.GetType().Name} occurred on subscription '{subscriptionDescription.Name}' creation for topic '{subscriptionDescription.TopicPath}' in namespace '{namespaceManager.Address.Host}'."; if (!ex.IsTransient) { logger.Fatal(loggedMessage, ex); throw; } logger.Info(loggedMessage, ex); } }
public async Task DeleteSubscription(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo) { var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName); // Check subscription with event name only is the one we should delete. If it's reused, then we need to use event full name. if (await SubscriptionIsReusedAcrossDifferentNamespaces(subscriptionDescription, sqlFilter, namespaceManager).ConfigureAwait(false)) { logger.Debug("Deleting subscription using event type full name"); subscriptionDescription = new SubscriptionDescription(topicPath, metadata.SubscriptionNameBasedOnEventWithNamespace); } // delete subscription based on event name only await creator.DeleteSubscription(subscriptionDescription.TopicPath, subscriptionDescription.Name, metadata, sqlFilter, namespaceManager, forwardTo).ConfigureAwait(false); }
public async Task <SubscriptionDescription> Create(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo = null) { var subscriptionDescription = await creator.Create(topicPath, subscriptionName, metadata, sqlFilter, namespaceManager, forwardTo).ConfigureAwait(false); if (await SubscriptionIsReusedAcrossDifferentNamespaces(subscriptionDescription, sqlFilter, namespaceManager).ConfigureAwait(false)) { logger.Debug("Creating subscription using event type full name"); subscriptionDescription = await creator.Create(topicPath, metadata.SubscriptionNameBasedOnEventWithNamespace, metadata, sqlFilter, namespaceManager, forwardTo).ConfigureAwait(false); } return(subscriptionDescription); }
public async Task <SubscriptionDescription> Create(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo) { if (!(metadata is ForwardingTopologySubscriptionMetadata meta)) { throw new InvalidOperationException($"Cannot create subscription `{subscriptionName}` for topic `{topicPath}` without namespace information required."); } var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName) { EnableBatchedOperations = subscriptionSettings.EnableBatchedOperations, AutoDeleteOnIdle = subscriptionSettings.AutoDeleteOnIdle, DefaultMessageTimeToLive = subscriptionSettings.DefaultMessageTimeToLive, EnableDeadLetteringOnFilterEvaluationExceptions = subscriptionSettings.EnableDeadLetteringOnFilterEvaluationExceptions, EnableDeadLetteringOnMessageExpiration = subscriptionSettings.EnableDeadLetteringOnMessageExpiration, LockDuration = subscriptionSettings.LockDuration, MaxDeliveryCount = DefaultMaxDeliveryCountForNoImmediateRetries }; if (subscriptionSettings.ForwardDeadLetteredMessagesToCondition(SubscriptionClient.FormatSubscriptionPath(topicPath, subscriptionName))) { subscriptionDescription.ForwardDeadLetteredMessagesTo = subscriptionSettings.ForwardDeadLetteredMessagesTo; } subscriptionSettings.DescriptionCustomizer(subscriptionDescription); subscriptionDescription.ForwardTo = forwardTo; subscriptionDescription.UserMetadata = metadata.Description; try { var exists = await ExistsAsync(topicPath, subscriptionName, metadata.Description, namespaceManager).ConfigureAwait(false); if (!exists) { var ruleDescription = new RuleDescription { Filter = new SqlFilter(sqlFilter), Name = metadata.SubscriptionNameBasedOnEventWithNamespace }; try { await namespaceManager.CreateSubscription(subscriptionDescription, ruleDescription).ConfigureAwait(false); logger.Info($"Subscription '{subscriptionDescription.UserMetadata}' created as '{subscriptionDescription.Name}' with rule '{ruleDescription.Name}' for event '{meta.SubscribedEventFullName}' in namespace '{namespaceManager.Address.Host}'."); var key = GenerateSubscriptionKey(namespaceManager.Address, subscriptionDescription.TopicPath, subscriptionDescription.Name); await rememberExistence.AddOrUpdate(key, keyNotFound => TaskEx.CompletedTrue, (updateTopicPath, previousValue) => TaskEx.CompletedTrue).ConfigureAwait(false); } catch (MessagingEntityAlreadyExistsException) { // the subscription already exists or another node beat us to it, which is ok logger.Info($"Subscription '{subscriptionDescription.Name}' in namespace '{namespaceManager.Address.Host}' already exists, another node probably beat us to it."); exists = true; } } if (exists) { logger.Info($"Subscription '{subscriptionDescription.Name}' aka '{subscriptionDescription.UserMetadata}' already exists, skipping creation."); logger.InfoFormat("Checking if subscription '{0}' in namespace '{1}' needs to be updated.", subscriptionDescription.Name, namespaceManager.Address.Host); var existingSubscriptionDescription = await namespaceManager.GetSubscription(subscriptionDescription.TopicPath, subscriptionDescription.Name).ConfigureAwait(false); if (MembersAreNotEqual(existingSubscriptionDescription, subscriptionDescription)) { logger.Info($"Updating subscription '{subscriptionDescription.Name}' in namespace '{namespaceManager.Address.Host}' with new description."); await namespaceManager.UpdateSubscription(subscriptionDescription).ConfigureAwait(false); } // Rules can't be queried, so try to add var ruleDescription = new RuleDescription { Filter = new SqlFilter(sqlFilter), Name = metadata.SubscriptionNameBasedOnEventWithNamespace }; logger.Info($"Adding subscription rule '{ruleDescription.Name}' for event '{meta.SubscribedEventFullName}' in namespace '{namespaceManager.Address.Host}'."); try { var subscriptionClient = SubscriptionClient.CreateFromConnectionString(meta.NamespaceInfo.ConnectionString, topicPath, subscriptionName); await subscriptionClient.AddRuleAsync(ruleDescription).ConfigureAwait(false); } catch (MessagingEntityAlreadyExistsException exception) { logger.Debug($"Rule '{ruleDescription.Name}' already exists. Response from the server: '{exception.Message}'."); } } } catch (TimeoutException) { logger.Info($"Timeout occurred on subscription creation for topic '{subscriptionDescription.TopicPath}' subscription name '{subscriptionDescription.Name}' in namespace '{namespaceManager.Address.Host}' going to validate if it doesn't exist."); // there is a chance that the timeout occurred, but the topic was still created, check again if (!await ExistsAsync(subscriptionDescription.TopicPath, subscriptionDescription.Name, metadata.Description, namespaceManager, removeCacheEntry: true).ConfigureAwait(false)) { throw; } logger.Info($"Looks like subscription '{subscriptionDescription.Name}' in namespace '{namespaceManager.Address.Host}' exists anyway."); } catch (MessagingException ex) { var loggedMessage = $"{(ex.IsTransient ? "Transient" : "Non transient")} {ex.GetType().Name} occurred on subscription '{subscriptionDescription.Name}' creation for topic '{subscriptionDescription.TopicPath}' in namespace '{namespaceManager.Address.Host}'."; if (!ex.IsTransient) { logger.Fatal(loggedMessage, ex); throw; } logger.Info(loggedMessage, ex); } return(subscriptionDescription); }
public async Task DeleteSubscription(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo) { var meta = metadata as ForwardingTopologySubscriptionMetadata; // var subscriptionDescription = subscriptionDescriptionFactory(topicPath, subscriptionName, settings); var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName); try { if (await ExistsAsync(topicPath, subscriptionName, metadata.Description, namespaceManager, removeCacheEntry: true).ConfigureAwait(false)) { var ruleDescription = new RuleDescription { Filter = new SqlFilter(sqlFilter), Name = metadata.SubscriptionNameBasedOnEventWithNamespace }; logger.Info($"Removing subscription rule '{ruleDescription.Name}' for event '{meta.SubscribedEventFullName}'."); var subscriptionClient = SubscriptionClient.CreateFromConnectionString(meta.NamespaceInfo.ConnectionString, topicPath, subscriptionName); await subscriptionClient.RemoveRuleAsync(ruleDescription.Name).ConfigureAwait(false); var remainingRules = await namespaceManager.GetRules(subscriptionDescription).ConfigureAwait(false); if (!remainingRules.Any()) { await namespaceManager.DeleteSubscription(subscriptionDescription).ConfigureAwait(false); logger.Debug($"Subscription '{metadata.Description}' created as '{subscriptionDescription.Name}' was removed as part of unsubscribe since events are subscribed to."); } } } catch (MessagingException ex) { var loggedMessage = $"{(ex.IsTransient ? "Transient" : "Non transient")} {ex.GetType().Name} occurred on subscription '{subscriptionDescription.Name}' deletion for topic '{subscriptionDescription.TopicPath}' in namespace '{namespaceManager.Address.Host}'."; if (!ex.IsTransient) { logger.Fatal(loggedMessage, ex); throw; } logger.Info(loggedMessage, ex); } }
public async Task <SubscriptionDescription> Create(string topicPath, string subscriptionName, SubscriptionMetadataInternal metadata, string sqlFilter, INamespaceManagerInternal namespaceManager, string forwardTo = null) { var subscriptionDescription = await creator.Create(topicPath, subscriptionName, metadata, sqlFilter, namespaceManager, forwardTo).ConfigureAwait(false); if (await SubscriptionIsReusedAcrossDifferentNamespaces(subscriptionDescription, sqlFilter, namespaceManager).ConfigureAwait(false)) { // Instead of adding new subscription, we're going to update the subscription filter instead, // since if there are 2 messages with same and different namespace, we provide merged filter capturing both of them. // subscriptionDescription = await creator.Create(topicPath, metadata.SubscriptionNameBasedOnEventWithNamespace, metadata, sqlFilter, namespaceManager, forwardTo).ConfigureAwait(false); logger.Debug("Updating the subscription filter."); await creator.UpdateFilter(topicPath, subscriptionName, sqlFilter, namespaceManager).ConfigureAwait(false); } return(subscriptionDescription); }