public void When_same_publisher_is_registered_multiple_times_should_remove_duplicates() { var publisherTable = new Publishers(); var pub1 = PublisherAddress.CreateFromEndpointName("Endpoint1"); var pub2 = PublisherAddress.CreateFromEndpointName("Endpoint1"); var pub3 = PublisherAddress.CreateFromEndpointInstances(new EndpointInstance("Instance1"), new EndpointInstance("Instance2")); var pub4 = PublisherAddress.CreateFromEndpointInstances(new EndpointInstance("Instance1"), new EndpointInstance("Instance2")); var pub5 = PublisherAddress.CreateFromPhysicalAddresses("address1", "address2"); var pub6 = PublisherAddress.CreateFromPhysicalAddresses("address1", "address2"); publisherTable.AddOrReplacePublishers("key2", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), pub1), new PublisherTableEntry(typeof(MyEvent), pub2), new PublisherTableEntry(typeof(MyEvent), pub3), new PublisherTableEntry(typeof(MyEvent), pub4), new PublisherTableEntry(typeof(MyEvent), pub5), new PublisherTableEntry(typeof(MyEvent), pub6) }); var pubs = publisherTable.GetPublisherFor(typeof(MyEvent)).ToArray(); Assert.AreEqual(3, pubs.Length); Assert.Contains(pub1, pubs); Assert.Contains(pub2, pubs); Assert.Contains(pub3, pubs); Assert.Contains(pub4, pubs); Assert.Contains(pub5, pubs); Assert.Contains(pub6, pubs); }
protected override void Setup(FeatureConfigurationContext context) { var transportInfra = context.Settings.Get <TransportInfrastructure>(); var nativePubSub = transportInfra.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Multicast; var settings = context.Settings.Get <RouterConnectionSettings>(); var unicastRouteTable = context.Settings.Get <UnicastRoutingTable>(); var route = UnicastRoute.CreateFromEndpointName(settings.RouterAddress); var publishers = context.Settings.Get <Publishers>(); var bindings = context.Settings.Get <QueueBindings>(); //Make sure router queue does exist. bindings.BindSending(settings.RouterAddress); //Send the specified messages through the router var routes = settings.SendRouteTable.Select(x => new RouteTableEntry(x.Key, route)).ToList(); unicastRouteTable.AddOrReplaceRoutes("NServiceBus.Router", routes); var distributorAddress = context.Settings.GetOrDefault <string>("LegacyDistributor.Address"); var subscriberAddress = distributorAddress ?? context.Settings.LocalAddress(); var publisherAddress = PublisherAddress.CreateFromPhysicalAddresses(settings.RouterAddress); publishers.AddOrReplacePublishers("NServiceBus.Router", settings.PublisherTable.Select(kvp => new PublisherTableEntry(kvp.Key, publisherAddress)).ToList()); context.Pipeline.Register(new ForwardSiteMessagesToRouterBehavior(settings.RouterAddress), "Routes messages sent to sites to the bridge."); context.Pipeline.Register(new RoutingHeadersBehavior(settings.SendRouteTable), "Sets the ultimate destination endpoint on the outgoing messages."); context.Pipeline.Register(b => new RouterSubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), settings.RouterAddress, b.Build <IDispatchMessages>(), settings.PublisherTable, nativePubSub), "Dispatches the subscribe request via a router."); context.Pipeline.Register(b => new RouterUnsubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), settings.RouterAddress, b.Build <IDispatchMessages>(), settings.PublisherTable, nativePubSub), "Dispatches the unsubscribe request via a router."); }
static void RegisterEventRoute(Type mappedType, string address, List <PublisherTableEntry> publisherTableEntries, IEnumerable <Type> baseTypes) { var publisherAddress = PublisherAddress.CreateFromPhysicalAddresses(address); publisherTableEntries.AddRange(baseTypes.Select(type => new PublisherTableEntry(type, publisherAddress))); publisherTableEntries.Add(new PublisherTableEntry(mappedType, publisherAddress)); }
async Task UpdateCaches(EndpointInstance instanceName, Type[] handledTypes, Type[] publishedTypes) { var newInstanceMap = BuildNewInstanceMap(instanceName); var newEndpointMap = BuildNewEndpointMap(instanceName.Endpoint, handledTypes, endpointMap); var newPublisherMap = BuildNewPublisherMap(instanceName, publishedTypes, publisherMap); LogChangesToEndpointMap(endpointMap, newEndpointMap); LogChangesToInstanceMap(instanceMap, newInstanceMap); var toSubscribe = LogChangesToPublisherMap(publisherMap, newPublisherMap).ToArray(); #region AddOrReplace routingTable.AddOrReplaceRoutes("AutomaticRouting", newEndpointMap.Select( x => new RouteTableEntry(x.Key, UnicastRoute.CreateFromEndpointName(x.Value))).ToList()); publishers.AddOrReplacePublishers("AutomaticRouting", newPublisherMap.Select( x => new PublisherTableEntry(x.Key, PublisherAddress.CreateFromEndpointName(x.Value))).ToList()); endpointInstances.AddOrReplaceInstances("AutomaticRouting", newInstanceMap.SelectMany(x => x.Value).ToList()); #endregion instanceMap = newInstanceMap; endpointMap = newEndpointMap; publisherMap = newPublisherMap; foreach (var type in toSubscribe.Intersect(messageTypesHandledByThisEndpoint)) { await messageSession.Subscribe(type) .ConfigureAwait(false); } }
public void When_subscribing_multiple_events_should_throw_aggregate_exception_with_all_failures() { var context = new TestableSubscribeContext { EventTypes = new[] { typeof(EventA), typeof(EventB) } }; // Marks this message as a SubscribeAll call context.Extensions.Set(MessageSession.SubscribeAllFlagKey, true); var state = context.Extensions.GetOrCreate <MessageDrivenSubscribeTerminator.Settings>(); state.MaxRetries = 0; state.RetryDelay = TimeSpan.Zero; dispatcher.FailDispatch(10); // no publisher for EventB publishers.AddOrReplacePublishers("Test", new List <PublisherTableEntry>() { new PublisherTableEntry(typeof(EventA), PublisherAddress.CreateFromPhysicalAddresses("publisher1")), }); var exception = Assert.ThrowsAsync <AggregateException>(() => subscribeTerminator.Invoke(context, c => Task.CompletedTask)); Assert.AreEqual(2, exception.InnerExceptions.Count); Assert.IsTrue(exception.InnerExceptions.Any(e => e is QueueNotFoundException)); // exception from dispatcher Assert.IsTrue(exception.InnerExceptions.Any(e => e.Message.Contains($"No publisher address could be found for message type '{typeof(EventB)}'"))); // exception from terminator }
public static void RegisterPublisher(this RoutingSettings config, Type eventType, string publisherEndpoint) { config.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers(Guid.NewGuid().ToString(), new List <PublisherTableEntry> { new PublisherTableEntry(eventType, PublisherAddress.CreateFromEndpointName(publisherEndpoint)) }); }
protected override void Setup(FeatureConfigurationContext context) { var rampSettings = context.Settings.Get <RampSettings>(); var unicastRouteTable = context.Settings.Get <UnicastRoutingTable>(); var route = UnicastRoute.CreateFromPhysicalAddress(rampSettings.BridgeAddress); var publishers = context.Settings.Get <Publishers>(); //Send the specified messages through the bridge var routes = rampSettings.SendRouteTable.Select(x => new RouteTableEntry(x.Key, route)).ToList(); unicastRouteTable.AddOrReplaceRoutes("NServiceBus.Bridge", routes); var distributorAddress = context.Settings.GetOrDefault <string>("LegacyDistributor.Address"); var subscriberAddress = distributorAddress ?? context.Settings.LocalAddress(); var publisherAddress = PublisherAddress.CreateFromPhysicalAddresses(rampSettings.BridgeAddress); publishers.AddOrReplacePublishers("Bridge", rampSettings.PublisherTable.Select(kvp => new PublisherTableEntry(kvp.Key, publisherAddress)).ToList()); context.Pipeline.Register(new SetUltimateDestinationEndpointBehavior(rampSettings.SendRouteTable), "Sets the ultimate destination endpoint on the outgoing messages."); context.Pipeline.Register(new SetCorrelationIdBehavior(), "Encodes the reply-to address in the correlation ID."); context.Pipeline.Register(b => new BridgeSubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), rampSettings.BridgeAddress, b.Build <IDispatchMessages>(), rampSettings.PublisherTable), "Dispatches the subscribe request to the bridge."); context.Pipeline.Register(b => new BridgeUnsubscribeBehavior(subscriberAddress, context.Settings.EndpointName(), rampSettings.BridgeAddress, b.Build <IDispatchMessages>(), rampSettings.PublisherTable), "Dispatches the unsubscribe request to the bridge."); }
public async Task It_should_still_deliver_once() { var context = await Scenario.Define <Context>() .WithEndpoint <Publisher>(b => b.When(c => c.Instance1SubscribedMessageDriven && c.Instance2SubscribedNative, (session, ctx) => session.Publish(new MyEvent()))) .WithEndpoint(new Subscriber(false), b => { b.CustomConfig(c => { c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(Conventions.EndpointNamingConvention(typeof(Publisher)))) }); }); b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); }); }) .WithEndpoint(new Subscriber(true), b => b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); ctx.Instance2SubscribedNative = true; })) .Done(c => c.EventReceived >= 1) .Run(); Assert.AreEqual(1, context.EventReceived); }
public void SetUp() { publishers = new Publishers(); publishers.AddOrReplacePublishers("A", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(object), PublisherAddress.CreateFromPhysicalAddresses("publisher1")) }); router = new SubscriptionRouter(publishers, new EndpointInstances(), i => i.ToString()); dispatcher = new FakeDispatcher(); subscribeTerminator = new MessageDrivenSubscribeTerminator(router, "replyToAddress", "Endpoint", dispatcher); }
public async Task Should_Dispatch_for_all_publishers() { publishers.AddOrReplacePublishers("B", new List <PublisherTableEntry>() { new PublisherTableEntry(typeof(object), PublisherAddress.CreateFromPhysicalAddresses("publisher2")) }); await subscribeTerminator.Invoke(new TestableSubscribeContext(), c => Task.CompletedTask); Assert.AreEqual(2, dispatcher.DispatchedTransportOperations.Count); }
protected override void Setup(FeatureConfigurationContext context) { var publishers = context.Settings.Get <Publishers>(); var publisherAddress = PublisherAddress.CreateFromEndpointName("PublisherEndpoint"); publishers.AddOrReplacePublishers("MySource", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), publisherAddress) }); }
public Subscriber() { EndpointSetup(new CustomizedServer(supportsNativeDelayedDelivery: true, supportsPublishSubscribe: false), (c, rd) => { c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); c.DisableFeature <AutoSubscribe>(); }); }
public Subscriber() { EndpointSetup(new CustomizedServer(ConnectionString, false), (c, sd) => { //SqlServerTransport no longer implements message-driven pub sub interface so we need to configure Publishers "manually" c.GetSettings().GetOrCreate<Publishers>().AddOrReplacePublishers("LegacyConfig", new List<PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); c.DisableFeature<AutoSubscribe>(); }); }
public void Without_best_practice_enforcement_it_throws_if_specified_assembly_contains_only_commands() { //Enforce artificial conventions to make sure the is a single command (but no messages) in an assembly var conventionBuilder = new ConventionsBuilder(new SettingsHolder()); conventionBuilder.DefiningCommandsAs(t => t == typeof(string)); var source = new AssemblyPublisherSource(typeof(string).Assembly, PublisherAddress.CreateFromEndpointName("Destination")); Assert.That(() => source.GenerateWithoutBestPracticeEnforcement(conventionBuilder.Conventions).ToArray(), Throws.Exception.Message.Contains("Cannot configure publisher for assembly")); }
public Subscriber() { EndpointSetup <DefaultServer>(c => { c.DisableFeature <AutoSubscribe>(); c.GetSettings().GetOrCreate <Publishers>() .AddOrReplacePublishers("CustomRoutingFeature", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); }); }
public Subscriber() { EndpointSetup <DefaultServer>(c => { c.GetSettings().Set("SqlServer.DisableNativePubSub", true); //SqlServerTransport no longer implements message-driven pub sub interface so we need to configure Publishers "manually" c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); c.DisableFeature <AutoSubscribe>(); }); }
public void When_group_does_not_exist_should_add_routes() { var publisherTable = new Publishers(); var publisher = PublisherAddress.CreateFromEndpointName("Endpoint1"); publisherTable.AddOrReplacePublishers("key", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), publisher), }); var retrievedPublisher = publisherTable.GetPublisherFor(typeof(MyEvent)).Single(); Assert.AreSame(publisher, retrievedPublisher); }
public async Task Should_dispatch_to_all_publishers_for_all_events() { var context = new TestableSubscribeContext() { EventTypes = new[] { typeof(EventA), typeof(EventB) } }; publishers.AddOrReplacePublishers("Test", new List <PublisherTableEntry>() { new PublisherTableEntry(typeof(EventA), PublisherAddress.CreateFromPhysicalAddresses("publisher1")), new PublisherTableEntry(typeof(EventA), PublisherAddress.CreateFromPhysicalAddresses("publisher2")), new PublisherTableEntry(typeof(EventB), PublisherAddress.CreateFromPhysicalAddresses("publisher1")), new PublisherTableEntry(typeof(EventB), PublisherAddress.CreateFromPhysicalAddresses("publisher2")) }); await subscribeTerminator.Invoke(context, c => Task.CompletedTask); Assert.AreEqual(4, dispatcher.DispatchedTransportOperations.Count); }
public void When_multiple_publishers_exist_should_return_all_of_them() { var publisherTable = new Publishers(); var pub1 = PublisherAddress.CreateFromEndpointName("Endpoint1"); var pub2 = PublisherAddress.CreateFromEndpointName("Endpoint2"); publisherTable.AddOrReplacePublishers("key2", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), pub1), }); publisherTable.AddOrReplacePublishers("key1", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), pub2), }); var pubs = publisherTable.GetPublisherFor(typeof(MyEvent)).ToArray(); Assert.Contains(pub1, pubs); Assert.Contains(pub2, pubs); }
protected override void Setup(FeatureConfigurationContext context) { var exchangeEndpointName = context.Settings.Get <string>(TopicExchangeEndpointNameKey); var transportInfrastructure = context.Settings.Get <TransportInfrastructure>(); var conventions = context.Settings.Get <Conventions>(); var publishers = context.Settings.Get <Publishers>(); var endpointInstances = context.Settings.Get <EndpointInstances>(); var distributionPolicy = context.Settings.Get <DistributionPolicy>(); var topicExchangeAddressManager = new TopicExchangeAddressManager( exchangeEndpointName, endpointInstances, i => transportInfrastructure.ToTransportAddress(LogicalAddress.CreateRemoteAddress(i)), distributionPolicy ); var eventTypes = context.Settings.GetAvailableTypes().Where(conventions.IsEventType).ToArray(); // Route all Subscription requests to the TopicExchange publishers.AddOrReplacePublishers( "TopicExchange", eventTypes.Select( e => new PublisherTableEntry(e, PublisherAddress.CreateFromEndpointName(exchangeEndpointName)) ).ToList() ); // Route a copy of all published events to the TopicExchange context.RegisterStartupTask(b => new SubscribeTopicExchangeToAllEvents( eventTypes, b.Build <ISubscriptionStorage>(), topicExchangeAddressManager )); // Forward all incoming Subscribe/Unsubscribe requests from legacy subscribers to the topic exchange context.Pipeline.Replace( "ProcessSubscriptionRequests", builder => new RerouteIncomingPubSubMessagesToTopicExchange(topicExchangeAddressManager), "Reroutes incoming Subscribe and Unsubscribe messages to the topic exchange"); }
protected override void Setup(FeatureConfigurationContext context) { var remoteAddresses = context.Settings.Get <string[]>("ServiceControl.RemoteInstances"); var typesToSubscribeTo = context.Settings.Get <Type[]>("ServiceControl.RemoteTypesToSubscribeTo"); var transportInfrastructure = context.Settings.Get <TransportInfrastructure>(); if (transportInfrastructure.OutboundRoutingPolicy.Publishes == OutboundRoutingType.Unicast) { var publishers = context.Settings.Get <Publishers>(); var remotePublishers = remoteAddresses.SelectMany(r => typesToSubscribeTo.Select(t => new PublisherTableEntry(t, PublisherAddress.CreateFromPhysicalAddresses(r)))); var localAddress = context.Settings.LocalAddress(); var publisherRoutes = remotePublishers.Concat(typesToSubscribeTo.Select(t => new PublisherTableEntry(t, PublisherAddress.CreateFromPhysicalAddresses(localAddress)))); publishers.AddOrReplacePublishers("ServiceControl", publisherRoutes.ToList()); } context.RegisterStartupTask(new SubscriptionStartupTask(typesToSubscribeTo)); }
public void Without_best_practice_enforcement_it_throws_if_specified_type_is_a_command() { var source = new TypePublisherSource(typeof(Command), PublisherAddress.CreateFromEndpointName("Destination")); Assert.That(() => source.GenerateWithoutBestPracticeEnforcement(new Conventions()).ToArray(), Throws.Exception.Message.Contains("because it is a command")); }
/// <summary> /// Creates a new entry. /// </summary> public PublisherTableEntry(Type eventType, PublisherAddress address) { EventType = eventType; Address = address; }
public AssemblyPublisherSource(Assembly messageAssembly, PublisherAddress address) { this.messageAssembly = messageAssembly; this.address = address; }
public void Without_best_practice_enforcement_it_throws_if_specified_type_is_not_a_message() { var source = new TypePublisherSource(typeof(NonMessage), PublisherAddress.CreateFromEndpointName("Destination")); Assert.That(() => source.GenerateWithoutBestPracticeEnforcement(new Conventions()).ToArray(), Throws.Exception.Message.Contains("it is not considered a message")); }
/// <summary> /// Registers a publisher endpoint for a given event type. /// </summary> /// <param name="routingSettings">The <see cref="RoutingSettings<T>" /> to extend.</param> /// <param name="eventType">The event type.</param> /// <param name="publisherEndpoint">The publisher endpoint.</param> public static void RegisterPublisher <T>(this RoutingSettings <T> routingSettings, Type eventType, string publisherEndpoint) where T : TransportDefinition, IMessageDrivenSubscriptionTransport { Guard.AgainstNullAndEmpty(nameof(publisherEndpoint), publisherEndpoint); ThrowOnAddress(publisherEndpoint); routingSettings.Settings.GetOrCreate <ConfiguredPublishers>().Add(new TypePublisherSource(eventType, PublisherAddress.CreateFromEndpointName(publisherEndpoint))); }
/// <summary> /// Registers a publisher endpoint for all event types in a given assembly and namespace. /// </summary> /// <param name="routingSettings">The <see cref="RoutingSettings<T>" /> to extend.</param> /// <param name="assembly">The assembly containing the event types.</param> /// <param name="namespace"> The namespace containing the event types. The given value must exactly match the target namespace.</param> /// <param name="publisherEndpoint">The publisher endpoint.</param> public static void RegisterPublisher <T>(this RoutingSettings <T> routingSettings, Assembly assembly, string @namespace, string publisherEndpoint) where T : TransportDefinition, IMessageDrivenSubscriptionTransport { Guard.AgainstNull(nameof(assembly), assembly); Guard.AgainstNullAndEmpty(nameof(publisherEndpoint), publisherEndpoint); ThrowOnAddress(publisherEndpoint); // empty namespace is null, not string.empty @namespace = @namespace == string.Empty ? null : @namespace; routingSettings.Settings.GetOrCreate <ConfiguredPublishers>().Add(new NamespacePublisherSource(assembly, @namespace, PublisherAddress.CreateFromEndpointName(publisherEndpoint))); }
/// <summary> /// Registers a publisher endpoint for all event types in a given assembly. /// </summary> /// <param name="assembly">The assembly containing the event types.</param> /// <param name="publisherEndpoint">The publisher endpoint.</param> public void RegisterPublisher(Assembly assembly, string publisherEndpoint) { Guard.AgainstNull(nameof(assembly), assembly); Guard.AgainstNullAndEmpty(nameof(publisherEndpoint), publisherEndpoint); ThrowOnAddress(publisherEndpoint); Settings.GetOrCreate <ConfiguredPublishers>().Add(new AssemblyPublisherSource(assembly, PublisherAddress.CreateFromEndpointName(publisherEndpoint))); }
/// <summary> /// Registers a publisher endpoint for all event types in a given assembly and namespace. /// </summary> /// <param name="assembly">The assembly containing the event types.</param> /// <param name="namespace"> The namespace containing the event types. The given value must exactly match the target namespace.</param> /// <param name="publisherEndpoint">The publisher endpoint.</param> public void RegisterPublisher(Assembly assembly, string @namespace, string publisherEndpoint) { Guard.AgainstNull(nameof(assembly), assembly); Guard.AgainstNullAndEmpty(nameof(publisherEndpoint), publisherEndpoint); ThrowOnAddress(publisherEndpoint); // empty namespace is null, not string.empty @namespace = @namespace == string.Empty ? null : @namespace; Settings.GetOrCreate <ConfiguredPublishers>().Add(new NamespacePublisherSource(assembly, @namespace, PublisherAddress.CreateFromEndpointName(publisherEndpoint))); }
public NamespacePublisherSource(Assembly messageAssembly, string messageNamespace, PublisherAddress address) { this.messageAssembly = messageAssembly; this.address = address; this.messageNamespace = messageNamespace; }
public TypePublisherSource(Type messageType, PublisherAddress address) { this.messageType = messageType; this.address = address; }
public async Task Should_not_lose_any_events() { var subscriptionStorage = new TestingInMemorySubscriptionStorage(); //Before migration begins var beforeMigration = await Scenario.Define <Context>() .WithEndpoint <Publisher>(b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); c.GetSettings().Set("SqlServer.DisableNativePubSub", true); }); b.When(c => c.SubscribedMessageDriven, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint <Subscriber>(b => { b.CustomConfig(c => { c.GetSettings().Set("SqlServer.DisableNativePubSub", true); c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); }); b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); }); }) .Done(c => c.GotTheEvent) .Run(TimeSpan.FromSeconds(30)); Assert.True(beforeMigration.GotTheEvent); //Publisher migrated and in compatibility mode var publisherMigrated = await Scenario.Define <Context>() .WithEndpoint <Publisher>(b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); c.GetSettings().Set("NServiceBus.Subscriptions.EnableMigrationMode", true); }); b.When(c => c.EndpointsStarted, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint <Subscriber>(b => { b.CustomConfig(c => { c.GetSettings().Set("SqlServer.DisableNativePubSub", true); c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); }); b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); }); }) .Done(c => c.GotTheEvent) .Run(TimeSpan.FromSeconds(30)); Assert.True(publisherMigrated.GotTheEvent); //Subscriber migrated and in compatibility mode var subscriberMigratedRunSettings = new RunSettings { TestExecutionTimeout = TimeSpan.FromSeconds(30) }; subscriberMigratedRunSettings.Set("DoNotCleanNativeSubscriptions", true); var subscriberMigrated = await Scenario.Define <Context>() .WithEndpoint <Publisher>(b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); c.GetSettings().Set("NServiceBus.Subscriptions.EnableMigrationMode", true); }); b.When(c => c.SubscribedMessageDriven && c.SubscribedNative, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint <Subscriber>(b => { b.CustomConfig(c => { c.GetSettings().Set("NServiceBus.Subscriptions.EnableMigrationMode", true); var compatModeSettings = new SubscriptionMigrationModeSettings(c.GetSettings()); compatModeSettings.RegisterPublisher(typeof(MyEvent), PublisherEndpoint); }); b.When(async(session, ctx) => { //Subscribes both using native feature and message-driven await session.Subscribe <MyEvent>(); ctx.SubscribedNative = true; }); }) .Done(c => c.GotTheEvent) .Run(subscriberMigratedRunSettings); Assert.True(subscriberMigrated.GotTheEvent); //Compatibility mode disabled in both publisher and subscriber var compatModeDisabled = await Scenario.Define <Context>() .WithEndpoint <Publisher>(b => { b.When(c => c.EndpointsStarted, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint <Subscriber>() .Done(c => c.GotTheEvent) .Run(TimeSpan.FromSeconds(30)); Assert.True(compatModeDisabled.GotTheEvent); }
public async Task Should_not_lose_any_events() { var subscriptionStorage = new TestingInMemorySubscriptionStorage(); //Before migration begins var beforeMigration = await Scenario.Define <Context>() .WithEndpoint(new Publisher(supportsPublishSubscribe: false), b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); }); b.When(c => c.SubscribedMessageDriven, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint(new Subscriber(supportsPublishSubscribe: false), b => { b.CustomConfig(c => { c.GetSettings().GetOrCreate <Publishers>().AddOrReplacePublishers("LegacyConfig", new List <PublisherTableEntry> { new PublisherTableEntry(typeof(MyEvent), PublisherAddress.CreateFromEndpointName(PublisherEndpoint)) }); }); b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); }); }) .Done(c => c.GotTheEvent) .Run(TimeSpan.FromSeconds(30)); Assert.True(beforeMigration.GotTheEvent); //Subscriber migrated and in compatibility mode. var subscriberMigratedRunSettings = new RunSettings { TestExecutionTimeout = TimeSpan.FromSeconds(30) }; var subscriberMigrated = await Scenario.Define <Context>() .WithEndpoint(new Publisher(supportsPublishSubscribe: false), b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); }); b.When(c => c.SubscribedMessageDriven, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint(new Subscriber(supportsPublishSubscribe: true), b => { b.CustomConfig(c => { var compatModeSettings = c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); compatModeSettings.RegisterPublisher(typeof(MyEvent), PublisherEndpoint); }); b.When(async(session, ctx) => { //Subscribes both using native feature and message-driven await session.Subscribe <MyEvent>(); ctx.SubscribedNative = true; }); }) .Done(c => c.GotTheEvent && c.SubscribedNative) //we ensure the subscriber did subscriber with the native mechanism .Run(subscriberMigratedRunSettings); Assert.True(subscriberMigrated.GotTheEvent); //Publisher migrated and in compatibility mode var publisherMigratedRunSettings = new RunSettings { TestExecutionTimeout = TimeSpan.FromSeconds(30) }; var publisherMigrated = await Scenario.Define <Context>() .WithEndpoint(new Publisher(supportsPublishSubscribe: true), b => { b.CustomConfig(c => { c.UsePersistence <TestingInMemoryPersistence, StorageType.Subscriptions>().UseStorage(subscriptionStorage); c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); }); b.When(c => c.SubscribedMessageDriven && c.SubscribedNative, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint(new Subscriber(supportsPublishSubscribe: true), b => { b.CustomConfig(c => { var compatModeSettings = c.ConfigureRouting().EnableMessageDrivenPubSubCompatibilityMode(); // not needed but left here to enforce duplicates compatModeSettings.RegisterPublisher(typeof(MyEvent), PublisherEndpoint); }); b.When(async(session, ctx) => { await session.Subscribe <MyEvent>(); ctx.SubscribedNative = true; }); }) .Done(c => c.GotTheEvent) .Run(publisherMigratedRunSettings); Assert.True(publisherMigrated.GotTheEvent); //Compatibility mode disabled in both publisher and subscriber var compatModeDisabled = await Scenario.Define <Context>() .WithEndpoint(new Publisher(supportsPublishSubscribe: true), b => { b.When(c => c.EndpointsStarted, (session, ctx) => session.Publish(new MyEvent())); }) .WithEndpoint(new Subscriber(supportsPublishSubscribe: true), c => { }) .Done(c => c.GotTheEvent) .Run(TimeSpan.FromSeconds(30)); Assert.True(compatModeDisabled.GotTheEvent); }