async Task <bool> ExistsAsync(INamespaceManagerInternal namespaceClient, string queuePath, bool removeCacheEntry = false)
        {
            var key = queuePath + namespaceClient.Address;

            logger.InfoFormat("Checking existence cache for '{0}'", queuePath);

            if (removeCacheEntry)
            {
                rememberExistence.TryRemove(key, out Task <bool> dummy);
            }

            var exists = await rememberExistence.GetOrAdd(key, s =>
            {
                logger.InfoFormat("Checking namespace for existence of the queue '{0}'", queuePath);
                return(namespaceClient.QueueExists(queuePath));
            }).ConfigureAwait(false);

            logger.InfoFormat("Determined, from cache, that the queue '{0}' {1}", queuePath, exists ? "exists" : "does not exist");

            return(exists);
        }
        async Task <bool> ExistsAsync(string topicPath, INamespaceManagerInternal namespaceClient, bool removeCacheEntry = false)
        {
            var key = topicPath + namespaceClient.Address;

            logger.InfoFormat("Checking existence cache for '{0}'", topicPath);

            if (removeCacheEntry)
            {
                Task <bool> dummy;
                rememberExistence.TryRemove(key, out dummy);
            }

            var exists = await rememberExistence.GetOrAdd(key, notFoundTopicPath =>
            {
                logger.InfoFormat("Checking namespace for existence of the topic '{0}'", topicPath);
                return(namespaceClient.TopicExists(topicPath));
            }).ConfigureAwait(false);

            logger.InfoFormat("Determined, from cache, that the topic '{0}' {1}", topicPath, exists ? "exists" : "does not exist");

            return(exists);
        }
        public async Task <QueueDescription> Create(string queuePath, INamespaceManagerInternal namespaceManager)
        {
            var description = new QueueDescription(queuePath)
            {
                LockDuration                           = queueSettings.LockDuration,
                MaxSizeInMegabytes                     = queueSettings.MaxSizeInMegabytes,
                RequiresDuplicateDetection             = queueSettings.RequiresDuplicateDetection,
                DefaultMessageTimeToLive               = queueSettings.DefaultMessageTimeToLive,
                EnableDeadLetteringOnMessageExpiration = queueSettings.EnableDeadLetteringOnMessageExpiration,
                DuplicateDetectionHistoryTimeWindow    = queueSettings.DuplicateDetectionHistoryTimeWindow,
                MaxDeliveryCount                       = DefaultMaxDeliveryCountForNoImmediateRetries,
                EnableBatchedOperations                = queueSettings.EnableBatchedOperations,
                EnablePartitioning                     = queueSettings.EnablePartitioning,
                SupportOrdering                        = queueSettings.SupportOrdering,
                AutoDeleteOnIdle                       = queueSettings.AutoDeleteOnIdle,
            };

            if (queueSettings.ForwardDeadLetteredMessagesToCondition(queuePath))
            {
                description.ForwardDeadLetteredMessagesTo = queueSettings.ForwardDeadLetteredMessagesTo;
            }

            queueSettings.DescriptionCustomizer(description);

            try
            {
                if (!await ExistsAsync(namespaceManager, description.Path).ConfigureAwait(false))
                {
                    await namespaceManager.CreateQueue(description).ConfigureAwait(false);

                    logger.InfoFormat("Queue '{0}' created", description.Path);

                    await rememberExistence.AddOrUpdate(description.Path, s => TaskEx.CompletedTrue, (s, b) => TaskEx.CompletedTrue).ConfigureAwait(false);
                }
                else
                {
                    logger.InfoFormat("Queue '{0}' already exists, skipping creation", description.Path);
                    logger.InfoFormat("Checking if queue '{0}' needs to be updated", description.Path);
                    if (IsSystemQueue(description.Path))
                    {
                        logger.InfoFormat("Queue '{0}' is a shared queue and should not be updated", description.Path);
                        return(description);
                    }
                    var existingDescription = await namespaceManager.GetQueue(description.Path).ConfigureAwait(false);

                    if (MembersAreNotEqual(existingDescription, description))
                    {
                        OverrideImmutableMembers(existingDescription, description);
                        logger.InfoFormat("Updating queue '{0}' with new description", description.Path);
                        await namespaceManager.UpdateQueue(description).ConfigureAwait(false);
                    }
                }
            }
            catch (MessagingEntityAlreadyExistsException)
            {
                // the queue already exists or another node beat us to it, which is ok
                logger.InfoFormat("Queue '{0}' already exists, another node probably beat us to it", description.Path);
            }
            catch (TimeoutException)
            {
                logger.InfoFormat("Timeout occurred on queue creation for '{0}' going to validate if it doesn't exist", description.Path);

                // there is a chance that the timeout occurred, but the topic was still created, check again
                if (!await ExistsAsync(namespaceManager, description.Path, removeCacheEntry: true).ConfigureAwait(false))
                {
                    throw;
                }

                logger.InfoFormat("Looks like queue '{0}' exists anyway", description.Path);
            }
            catch (MessagingException ex)
            {
                if (!ex.IsTransient)
                {
                    logger.Fatal(string.Format("{1} {2} occurred on queue creation {0}", description.Path, ex.IsTransient ? "Transient" : "Non transient", ex.GetType().Name), ex);
                    throw;
                }

                logger.Info(string.Format("{1} {2} occurred on queue creation {0}", description.Path, ex.IsTransient ? "Transient" : "Non transient", ex.GetType().Name), ex);
            }

            return(description);
        }
        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);
        }
        async Task <bool> ExistsAsync(string topicPath, string subscriptionName, string metadata, INamespaceManagerInternal namespaceClient, bool removeCacheEntry = false)
        {
            logger.Info($"Checking existence cache for subscription '{subscriptionName}' in namespace '{namespaceClient.Address.Host}' aka '{metadata}'.");

            var key = GenerateSubscriptionKey(namespaceClient.Address, topicPath, subscriptionName);

            if (removeCacheEntry)
            {
                Task <bool> dummy;
                rememberExistence.TryRemove(key, out dummy);
            }

            var exists = await rememberExistence.GetOrAdd(key, notFoundKey =>
            {
                logger.InfoFormat("Checking namespace for existence of subscription '{0}' for the topic '{1}' in namespace '{2}'.", subscriptionName, topicPath, namespaceClient.Address.Host);
                return(namespaceClient.SubscriptionExists(topicPath, subscriptionName));
            }).ConfigureAwait(false);

            logger.InfoFormat("Determined, from cache, that the subscription '{0}' in namespace '{2}' {1}.", subscriptionName, exists ? "exists" : "does not exist", namespaceClient.Address.Host);

            return(exists);
        }
        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);
            }
        }
Пример #7
0
        async Task <bool> SubscriptionIsReusedAcrossDifferentNamespaces(SubscriptionDescription subscriptionDescription, string sqlFilter, INamespaceManagerInternal namespaceManager)
        {
            var rules = await namespaceManager.GetRules(subscriptionDescription).ConfigureAwait(false);

            var filter = rules.First().Filter as SqlFilter;

            if (filter != null && filter.SqlExpression != sqlFilter)
            {
                logger.Debug("Looks like this subscription name is already taken as the sql filter does not match the subscribed event name.");
                return(true);
            }

            return(false);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
 public Task UpdateFilter(string topicPath, string subscriptionName, string sqlFilter, INamespaceManagerInternal namespaceManager) =>
 namespaceManager.UpdateRule(topicPath, subscriptionName, new RuleDescription("$Default", new SqlFilter(sqlFilter)));
        public async Task <TopicDescription> Create(string topicPath, INamespaceManagerInternal namespaceManager)
        {
            var topicDescription = new TopicDescription(topicPath)
            {
                SupportOrdering                         = topicSettings.SupportOrdering,
                MaxSizeInMegabytes                      = topicSettings.MaxSizeInMegabytes,
                DefaultMessageTimeToLive                = topicSettings.DefaultMessageTimeToLive,
                RequiresDuplicateDetection              = topicSettings.RequiresDuplicateDetection,
                DuplicateDetectionHistoryTimeWindow     = topicSettings.DuplicateDetectionHistoryTimeWindow,
                EnableBatchedOperations                 = topicSettings.EnableBatchedOperations,
                EnablePartitioning                      = topicSettings.EnablePartitioning,
                AutoDeleteOnIdle                        = topicSettings.AutoDeleteOnIdle,
                EnableFilteringMessagesBeforePublishing = topicSettings.EnableFilteringMessagesBeforePublishing
            };

            topicSettings.DescriptionCustomizer(topicDescription);

            try
            {
                if (!await ExistsAsync(topicPath, namespaceManager).ConfigureAwait(false))
                {
                    await namespaceManager.CreateTopic(topicDescription).ConfigureAwait(false);

                    logger.InfoFormat("Topic '{0}' created", topicDescription.Path);
                    await rememberExistence.AddOrUpdate(topicDescription.Path, notFoundTopicPath => TaskEx.CompletedTrue, (updateTopicPath, previousValue) => TaskEx.CompletedTrue).ConfigureAwait(false);
                }
                else
                {
                    logger.InfoFormat("Topic '{0}' already exists, skipping creation", topicDescription.Path);
                    logger.InfoFormat("Checking if topic '{0}' needs to be updated", topicDescription.Path);
                    var existingTopicDescription = await namespaceManager.GetTopic(topicDescription.Path).ConfigureAwait(false);

                    if (MembersAreNotEqual(existingTopicDescription, topicDescription))
                    {
                        OverrideImmutableMembers(existingTopicDescription, topicDescription);
                        logger.InfoFormat("Updating topic '{0}' with new description", topicDescription.Path);
                        await namespaceManager.UpdateTopic(topicDescription).ConfigureAwait(false);
                    }
                }
            }
            catch (MessagingEntityAlreadyExistsException)
            {
                // the topic already exists or another node beat us to it, which is ok
                logger.InfoFormat("Topic '{0}' already exists, another node probably beat us to it", topicDescription.Path);
            }
            catch (TimeoutException)
            {
                logger.InfoFormat("Timeout occurred on topic creation for '{0}' going to validate if it doesn't exist", topicDescription.Path);

                // there is a chance that the timeout occurred, but the topic was still created, check again
                if (!await ExistsAsync(topicDescription.Path, namespaceManager, removeCacheEntry: true).ConfigureAwait(false))
                {
                    throw;
                }

                logger.InfoFormat("Looks like topic '{0}' exists anyway", topicDescription.Path);
            }
            catch (MessagingException ex)
            {
                var loggedMessage = string.Format("{1} {2} occurred on topic creation {0}", topicDescription.Path, ex.IsTransient ? "Transient" : "Non transient", ex.GetType().Name);

                if (!ex.IsTransient)
                {
                    logger.Fatal(loggedMessage, ex);
                    throw;
                }

                logger.Info(loggedMessage, ex);
            }

            return(topicDescription);
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
            }
        }
Пример #14
0
        async Task <bool> SubscriptionIsReusedAcrossDifferentNamespaces(SubscriptionDescription subscriptionDescription, string sqlFilter, INamespaceManagerInternal namespaceManager)
        {
            var foundRules = await namespaceManager.GetRules(subscriptionDescription).ConfigureAwait(false);

            var rules = foundRules as RuleDescription[] ?? foundRules.ToArray();

            if (rules.First().Filter is SqlFilter filter)
            {
                if (!filter.SqlExpression.Contains(sqlFilter))
                {
                    logger.Debug("Looks like this subscription name is already taken as the sql filter does not match the subscribed event name.");
                    return(true);
                }

                if (sqlFilter.Length != filter.SqlExpression.Length && rules.Length == 1)
                {
                    logger.Info($"SQL filter of the existing subscription '{subscriptionDescription.Name}' should be optimized.\nUpdate Rule filter from \"{filter.SqlExpression}\" to \"{sqlFilter}\".");
                }
            }

            return(false);
        }
Пример #15
0
        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);
        }
        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));
        }