NamespaceInfo SelectMostAppropriateReplyToNamespace(RuntimeNamespaceInfo destinationNamespace) { var selected = destinationNamespace != null?namespaceConfigurations.FirstOrDefault(ns => ns.Alias == destinationNamespace.Alias) : null; if (selected == null) { selected = namespaceConfigurations.FirstOrDefault(ns => ns.Alias == defaultAlias); } if (selected == null) { selected = namespaceConfigurations.FirstOrDefault(ns => ns.Purpose == NamespacePurpose.Partitioning); } return(selected); }
NamespaceInfo SelectMostAppropriateReplyToNamespace(RuntimeNamespaceInfo destinationNamespace) { var namespaces = settings.Get <NamespaceConfigurations>(WellKnownConfigurationKeys.Topology.Addressing.Namespaces).Where(n => n.Purpose == NamespacePurpose.Partitioning).ToList(); var defaultAlias = settings.Get <string>(WellKnownConfigurationKeys.Topology.Addressing.DefaultNamespaceAlias); var selected = destinationNamespace != null?namespaces.FirstOrDefault(ns => ns.Alias == destinationNamespace.Alias) : null; if (selected == null) { selected = namespaces.FirstOrDefault(ns => ns.Alias == defaultAlias); } if (selected == null) { selected = namespaces.FirstOrDefault(ns => ns.Purpose == NamespacePurpose.Partitioning); } return(selected); }
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 }); }
void SetReplyToAddress(OutgoingMessage outgoingMessage, BrokeredMessage brokeredMessage, RuntimeNamespaceInfo destinationNamespace) { if (outgoingMessage.Headers.ContainsKey(Headers.ReplyToAddress)) { var replyToAddress = outgoingMessage.Headers[Headers.ReplyToAddress]; // Read-only endpoints have no reply-to value if (string.IsNullOrWhiteSpace(replyToAddress)) { return; } var replyTo = new EntityAddress(replyToAddress); if (!replyTo.HasSuffix) { var useAliases = settings.Get <bool>(WellKnownConfigurationKeys.Topology.Addressing.UseNamespaceAliasesInsteadOfConnectionStrings); var selected = SelectMostAppropriateReplyToNamespace(destinationNamespace); if (selected != null) { if (useAliases) { replyTo = new EntityAddress(replyTo.Name, selected.Alias); } else { replyTo = new EntityAddress(replyTo.Name, selected.ConnectionString); } } } var replyToAsString = replyTo.ToString(); brokeredMessage.ReplyTo = replyToAsString; } }