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 }); }