Exemplo n.º 1
0
        TopologySectionInternal BuildSubscriptionHierarchy(Type eventType, string localAddress)
        {
            var namespaces = namespacePartitioningStrategy.GetNamespaces(PartitioningIntent.Creating).ToArray();

            // Using localAddress that will be provided by SubscriptionManager instead of the endpoint name.
            // Reason: endpoint name can be overridden. If the endpoint name is overridden, "originalEndpointName" will not have the override value.
            var sanitizedInputQueuePath   = addressingLogic.Apply(localAddress, EntityType.Queue).Name;
            var sanitizedSubscriptionPath = addressingLogic.Apply(localAddress, EntityType.Subscription).Name;

            // rule name needs to be 1) based on event full name 2) unique 3) deterministic
            var ruleName = addressingLogic.Apply(eventType.FullName, EntityType.Rule).Name;

            var subs   = new List <SubscriptionInfoInternal>();
            var topics = CreateTopics(namespaces);

            foreach (var topic in topics)
            {
                subs.AddRange(namespaces.Select(ns =>
                {
                    var sub = new SubscriptionInfoInternal
                    {
                        Namespace = ns,
                        Type      = EntityType.Subscription,
                        Path      = sanitizedSubscriptionPath,
                        Metadata  = new ForwardingTopologySubscriptionMetadata
                        {
                            Description = $"Events {originalEndpointName} is subscribed to",
                            SubscriptionNameBasedOnEventWithNamespace = ruleName,
                            NamespaceInfo           = ns,
                            SubscribedEventFullName = eventType.FullName
                        },
                        BrokerSideFilter   = new SqlSubscriptionFilter(eventType),
                        ShouldBeListenedTo = false
                    };
                    sub.RelationShips.Add(new EntityRelationShipInfoInternal
                    {
                        Source = sub,
                        Target = topic,
                        Type   = EntityRelationShipTypeInternal.Subscription
                    });
                    sub.RelationShips.Add(new EntityRelationShipInfoInternal
                    {
                        Source = sub,
                        Target = new EntityInfoInternal
                        {
                            Namespace = ns,
                            Path      = sanitizedInputQueuePath,
                            Type      = EntityType.Queue
                        },
                        Type = EntityRelationShipTypeInternal.Forward
                    });
                    return(sub);
                }));
            }
            return(new TopologySectionInternal
            {
                Entities = subs,
                Namespaces = namespaces
            });
        }
        void CreateForwardingTopologyPart(Type eventType, List <SubscriptionInfoInternal> subs, RuntimeNamespaceInfo[] namespaces, string sanitizedSubscriptionPath, string ruleName, string sanitizedInputQueuePath)
        {
            subs.AddRange(namespaces.Select(ns =>
            {
                var sub = new SubscriptionInfoInternal
                {
                    Namespace = ns,
                    Type      = EntityType.Subscription,
                    Path      = sanitizedSubscriptionPath,
                    Metadata  = new ForwardingTopologySubscriptionMetadata
                    {
                        Description = $"Events {originalEndpointName} is subscribed to",
                        SubscriptionNameBasedOnEventWithNamespace = ruleName,
                        NamespaceInfo           = ns,
                        SubscribedEventFullName = eventType.FullName
                    },
                    BrokerSideFilter   = new SqlSubscriptionFilter(eventType),
                    ShouldBeListenedTo = false
                };
                sub.RelationShips.Add(new EntityRelationShipInfoInternal
                {
                    Source = sub,
                    Target = new EntityInfoInternal
                    {
                        Namespace = ns,
                        Path      = "bundle-1",
                        Type      = EntityType.Topic
                    },
                    Type = EntityRelationShipTypeInternal.Subscription
                });
                sub.RelationShips.Add(new EntityRelationShipInfoInternal
                {
                    Source = sub,
                    Target = new EntityInfoInternal
                    {
                        Namespace = ns,
                        Path      = sanitizedInputQueuePath,
                        Type      = EntityType.Queue
                    },
                    Type = EntityRelationShipTypeInternal.Forward
                });

                return(sub);
            }));
        }
        public TopologySectionInternal DetermineTopicsToCreate(string localAddress)
        {
            var namespaces = namespacePartitioningStrategy.GetNamespaces(PartitioningIntent.Creating).ToArray();
            var entities   = new List <EntityInfoInternal>();

            foreach (var n in namespaces)
            {
                // legacy topic
                entities.Add(new EntityInfoInternal
                {
                    Path      = addressingLogic.Apply(localAddress + ".events", EntityType.Topic).Name,
                    Type      = EntityType.Topic,
                    Namespace = n
                });
                // bundle from forwarding
                entities.Add(new EntityInfoInternal
                {
                    Path      = "bundle-1",
                    Type      = EntityType.Topic,
                    Namespace = n
                });
                // migration
                // Dedup is defined in custom descriptor override, ugly yes but necessary evil
                entities.Add(new EntityInfoInternal
                {
                    Path      = MigrationTopicName,
                    Type      = EntityType.Topic,
                    Namespace = n
                });
                var subscription = new SubscriptionInfoInternal
                {
                    Namespace = n,
                    Type      = EntityType.Subscription,
                    Path      = MigrationTopicName,
                    Metadata  = new SubscriptionMetadataInternal
                    {
                        Description = "Forwarding to bundle-1",
                        SubscriptionNameBasedOnEventWithNamespace = MigrationTopicName
                    },
                    BrokerSideFilter   = new CatchAllSubscriptionFilter(),
                    ShouldBeListenedTo = false
                };
                subscription.RelationShips.Add(new EntityRelationShipInfoInternal
                {
                    Source = subscription,
                    Target = new EntityInfoInternal
                    {
                        Namespace = n,
                        Path      = MigrationTopicName,
                        Type      = EntityType.Topic
                    },
                    Type = EntityRelationShipTypeInternal.Subscription
                });
                subscription.RelationShips.Add(new EntityRelationShipInfoInternal
                {
                    Source = subscription,
                    Target = new EntityInfoInternal
                    {
                        Namespace = n,
                        Path      = "bundle-1",
                        Type      = EntityType.Topic
                    },
                    Type = EntityRelationShipTypeInternal.Forward
                });

                entities.Add(subscription);
            }

            return(new TopologySectionInternal
            {
                Namespaces = namespaces,
                Entities = entities
            });
        }
        TopologySectionInternal BuildSubscriptionHierarchy(Type eventType, string localAddress)
        {
            var namespaces = namespacePartitioningStrategy.GetNamespaces(PartitioningIntent.Creating).ToArray();

            var publishers = publishersConfiguration.GetPublishersFor(eventType);

            // Using localAddress that will be provided by SubscriptionManager instead of the endpoint name.
            // Reason: endpoint name can be overridden. If the endpoint name is overridden, "originalEndpointName" will not have the override value.
            var subscriptionNameCandidateV6 = $"{localAddress}.{eventType.Name}";
            var subscriptionNameV6          = addressingLogic.Apply(subscriptionNameCandidateV6, EntityType.Subscription).Name;
            var subscriptionNameCandidate   = $"{localAddress}.{eventType.FullName}";
            var subscriptionName            = addressingLogic.Apply(subscriptionNameCandidate, EntityType.Subscription).Name;

            // Using localAddress that will be provided by SubscriptionManager instead of the endpoint name.
            // Reason: endpoint name can be overridden. If the endpoint name is overridden, "originalEndpointName" will not have the override value.
            var sanitizedInputQueuePath   = addressingLogic.Apply(localAddress, EntityType.Queue).Name;
            var sanitizedSubscriptionPath = addressingLogic.Apply(localAddress, EntityType.Subscription).Name;

            var ruleName = addressingLogic.Apply(eventType.FullName, EntityType.Rule).Name;

            var topics = new List <EntityInfoInternal>();
            var subs   = new List <SubscriptionInfoInternal>();

            foreach (var publisher in publishers)
            {
                var topicPath = $"{publisher}.events";
                var path      = addressingLogic.Apply(topicPath, EntityType.Topic).Name;

                var destinationsOutsideTopology = namespaceConfigurations.Where(c => c.RegisteredEndpoints.Contains(publisher, StringComparer.OrdinalIgnoreCase)).ToList();
                if (destinationsOutsideTopology.Any())
                {
                    // It's important to create Forwarding topology subscription infrastructure first in order not to lose messages in flight auto-forwarded by subscriptions under Endpoint-oriented topology
                    CreateForwardingTopologyPart(eventType, subs, namespaces, sanitizedSubscriptionPath, ruleName, sanitizedInputQueuePath);

                    topics.AddRange(destinationsOutsideTopology.Select(ns => new EntityInfoInternal
                    {
                        Namespace = new RuntimeNamespaceInfo(ns.Alias, ns.Connection, NamespacePurpose.Routing),
                        Type      = EntityType.Topic,
                        Path      = path
                    }));

                    subs.AddRange(destinationsOutsideTopology.Select(ns =>
                    {
                        var rns = new RuntimeNamespaceInfo(ns.Alias, ns.Connection, NamespacePurpose.Routing);
                        var sub = new SubscriptionInfoInternal
                        {
                            Namespace = rns,
                            Type      = EntityType.Subscription,
                            Path      = subscriptionNameV6,
                            Metadata  = new SubscriptionMetadataInternal
                            {
                                Description = $"{originalEndpointName} subscribed to {eventType.FullName}",
                                SubscriptionNameBasedOnEventWithNamespace = subscriptionName
                            },
                            BrokerSideFilter   = new SqlSubscriptionFilter(eventType),
                            ShouldBeListenedTo = false
                        };
                        sub.RelationShips.Add(new EntityRelationShipInfoInternal
                        {
                            Source = sub,
                            Target = topics.First(t => t.Path == path && t.Namespace == rns),
                            Type   = EntityRelationShipTypeInternal.Subscription
                        });
                        sub.RelationShips.Add(new EntityRelationShipInfoInternal
                        {
                            Source = sub,
                            Target = new EntityInfoInternal
                            {
                                Namespace = new RuntimeNamespaceInfo(ns.Alias, ns.Connection),
                                Path      = MigrationTopicName,
                                Type      = EntityType.Topic
                            },
                            Type = EntityRelationShipTypeInternal.Forward
                        });
                        return(sub);
                    }));
                }
                else
                {
                    // It's important to create Forwarding topology subscription infrastructure first in order not to lose messages in flight auto-forwarded by subscriptions under Endpoint-oriented topology
                    CreateForwardingTopologyPart(eventType, subs, namespaces, sanitizedSubscriptionPath, ruleName, sanitizedInputQueuePath);

                    topics.AddRange(namespaces.Select(ns => new EntityInfoInternal
                    {
                        Namespace = ns,
                        Type      = EntityType.Topic,
                        Path      = path
                    }));

                    subs.AddRange(namespaces.Select(ns =>
                    {
                        var sub = new SubscriptionInfoInternal
                        {
                            Namespace = ns,
                            Type      = EntityType.Subscription,
                            Path      = subscriptionNameV6,
                            Metadata  = new SubscriptionMetadataInternal
                            {
                                Description = $"{originalEndpointName} subscribed to {eventType.FullName}",
                                SubscriptionNameBasedOnEventWithNamespace = subscriptionName
                            },
                            BrokerSideFilter   = new SqlSubscriptionFilter(eventType),
                            ShouldBeListenedTo = false
                        };
                        sub.RelationShips.Add(new EntityRelationShipInfoInternal
                        {
                            Source = sub,
                            Target = topics.First(t => t.Path == path && t.Namespace == ns),
                            Type   = EntityRelationShipTypeInternal.Subscription
                        });
                        sub.RelationShips.Add(new EntityRelationShipInfoInternal
                        {
                            Source = sub,
                            Target = new EntityInfoInternal
                            {
                                Namespace = ns,
                                Path      = MigrationTopicName,
                                Type      = EntityType.Topic
                            },
                            Type = EntityRelationShipTypeInternal.Forward
                        });

                        return(sub);
                    }));
                }
            }

            return(new TopologySectionInternal
            {
                Entities = subs,
                Namespaces = namespaces
            });
        }