public void SubscriptionWithExistingCursorGetsAllMessagesAfterMessageBusRestart() { var sp = ServiceProviderHelper.CreateServiceProvider(); using (var bus = (MessageBus)sp.GetRequiredService <IMessageBus>()) { var subscriber = new TestSubscriber(new[] { "key" }); var wh = new ManualResetEvent(false); IDisposable subscription = null; try { subscription = bus.Subscribe(subscriber, "d-key,00000001", (result, state) => { foreach (var m in result.GetMessages()) { Assert.Equal("key", m.Key); Assert.Equal("value", m.GetString()); wh.Set(); } return(TaskAsyncHelper.True); }, 10, null); bus.Publish("test", "key", "value"); Assert.True(wh.WaitOne(TimeSpan.FromSeconds(5))); } finally { if (subscription != null) { subscription.Dispose(); } } } }
public void GarbageCollectingTopicsAfterGettingTopicsNoops() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { services.ConfigureSignalR(options => { options.Transports.KeepAlive = null; }); }); using (var bus = (MessageBus)sp.GetRequiredService <IMessageBus>()) { var subscriber = new TestSubscriber(new[] { "key" }); IDisposable subscription = null; bus.AfterTopicMarkedSuccessfully = (key, topic) => { bus.GarbageCollectTopics(); }; try { subscription = bus.Subscribe(subscriber, null, (result, state) => TaskAsyncHelper.True, 10, null); Assert.Equal(1, bus.Topics.Count); Topic topic; Assert.True(bus.Topics.TryGetValue("key", out topic)); Assert.Equal(TopicState.HasSubscriptions, topic.State); } finally { if (subscription != null) { subscription.Dispose(); } } } }
public void GarbageCollectingTopicsBeforeSubscribingTopicSetsStateToHasSubscription() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { services.SetupOptions <SignalROptions>(options => { options.Transports.DisconnectTimeout = TimeSpan.FromSeconds(6); options.Transports.KeepAlive = null; }); }); using (var bus = (MessageBus)sp.GetService <IMessageBus>()) { bus.BeforeTopicMarked = (key, t) => { bus.GarbageCollectTopics(); }; Topic topic = bus.SubscribeTopic("key"); Assert.Equal(1, bus.Topics.Count); Assert.True(bus.Topics.TryGetValue("key", out topic)); Assert.Equal(TopicState.HasSubscriptions, topic.State); } }
public void SubscribingTopicAfterNoSubscriptionsStateSetsStateToHasSubscription() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { services.SetupOptions <SignalROptions>(options => { options.Transports.DisconnectTimeout = TimeSpan.FromSeconds(6); }); }); using (var bus = (MessageBus)sp.GetService <IMessageBus>()) { var subscriber = new TestSubscriber(new[] { "key" }); // Make sure the topic is in the no subs state bus.Subscribe(subscriber, null, (result, state) => TaskAsyncHelper.True, 10, null) .Dispose(); Topic topic = bus.SubscribeTopic("key"); Assert.Equal(1, bus.Topics.Count); Assert.True(bus.Topics.TryGetValue("key", out topic)); Assert.Equal(TopicState.HasSubscriptions, topic.State); } }
public void SubscriptionWithMultipleExistingCursors() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { var passThroughMinfier = new PassThroughStringMinifier(); services.AddInstance <IStringMinifier>(passThroughMinfier); }); using (var bus = (MessageBus)sp.GetService <IMessageBus>()) { Func <ISubscriber> subscriberFactory = () => new TestSubscriber(new[] { "key", "key2" }); var cdKey = new CountDownRange <int>(Enumerable.Range(2, 4)); var cdKey2 = new CountDownRange <int>(new[] { 1, 2, 10 }); IDisposable subscription = null; string prefix = DefaultSubscription._defaultCursorPrefix; // Pretend like we had an initial subscription bus.Subscribe(subscriberFactory(), null, (result, state) => TaskAsyncHelper.True, 10, null) .Dispose(); // This simulates a reconnect bus.Publish("test", "key", "1").Wait(); bus.Publish("test", "key", "2").Wait(); bus.Publish("test", "key", "3").Wait(); bus.Publish("test", "key", "4").Wait(); bus.Publish("test", "key2", "1").Wait(); bus.Publish("test", "key2", "2").Wait(); try { subscription = bus.Subscribe(subscriberFactory(), prefix + "key,00000001|key2,00000000", (result, state) => { foreach (var m in result.GetMessages()) { int n = Int32.Parse(m.GetString()); if (m.Key == "key") { Assert.True(cdKey.Mark(n)); } else { Assert.True(cdKey2.Mark(n)); } } return(TaskAsyncHelper.True); }, 10, null); bus.Publish("test", "key", "5"); bus.Publish("test", "key2", "10"); Assert.True(cdKey.Wait(TimeSpan.FromSeconds(5))); Assert.True(cdKey2.Wait(TimeSpan.FromSeconds(5))); } finally { if (subscription != null) { subscription.Dispose(); } } } }
public void MultipleSubscribeTopicCallsToDeadTopicWork() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { services.SetupOptions <SignalROptions>(options => { options.Transports.DisconnectTimeout = TimeSpan.FromSeconds(6); options.Transports.KeepAlive = null; }); }); var ta = new TypeActivator(); Topic topic; using (var bus = ta.CreateInstance <TestMessageBus>(sp)) { var subscriber = new TestSubscriber(new[] { "key" }); int count = 0; // Make sure the topic is in the no subs state bus.Subscribe(subscriber, null, (result, state) => TaskAsyncHelper.True, 10, null) .Dispose(); bus.BeforeTopicCreated = (key) => { bus.Topics.TryGetValue(key, out topic); if (count == 1) { // Should have been removed by our double garbage collect in BeforeTopicMarked Assert.Null(topic); } if (count == 3) { // Ensure that we have a topic now created from the original thread Assert.NotNull(topic); } }; bus.BeforeTopicMarked = (key, t) => { count++; if (count == 1) { bus.GarbageCollectTopics(); bus.GarbageCollectTopics(); // We garbage collect twice to mark the current topic as dead (it will remove it from the topics list) Assert.Equal(t.State, TopicState.Dead); bus.SubscribeTopic("key"); // Topic should still be dead Assert.Equal(t.State, TopicState.Dead); Assert.Equal(count, 2); // Increment up to 3 so we don't execute same code path in after marked count++; } if (count == 2) { // We've just re-created the topic from the second bus.SubscribeTopic so we should have 0 subscriptions Assert.Equal(t.State, TopicState.NoSubscriptions); } if (count == 4) { // Ensure that we pulled the already created subscription (therefore it has subscriptions) Assert.Equal(t.State, TopicState.HasSubscriptions); } }; bus.AfterTopicMarked = (key, t, state) => { if (count == 2) { // After re-creating the topic from the second bus.SubscribeTopic we should then move the topic state // into the has subscriptions state Assert.Equal(state, TopicState.HasSubscriptions); } if (count == 3) { Assert.Equal(state, TopicState.Dead); } }; bus.SubscribeTopic("key"); Assert.Equal(1, bus.Topics.Count); Assert.True(bus.Topics.TryGetValue("key", out topic)); Assert.Equal(TopicState.HasSubscriptions, topic.State); } }
public void SubscriptionDoesNotGetNewMessagesWhenTopicStoreOverrunByOtherStream() { var sp = ServiceProviderHelper.CreateServiceProvider(services => { services.SetupOptions <SignalROptions>(options => { options.MessageBus.MessageBufferSize = 10; }); }); var ta = new TypeActivator(); using (var bus = ta.CreateInstance <TestScaleoutBus>(sp, 2)) { var subscriber = new TestSubscriber(new[] { "key" }); IDisposable subscription = null; // The min fragment size is 8 and min fragments is 5 var expectedValues = Enumerable.Range(171, 8); var cd = new OrderedCountDownRange <int>(expectedValues); // This will overwrite the buffer ending up with (40 - 79) for stream 2 for (int i = 0; i < 80; i++) { bus.Publish(0, (ulong)i, new[] { new Message("test", "key", i.ToString()) }); } // This will overwrite the buffer with (140 - 179) for stream 1 for (int i = 100; i < 180; i++) { bus.Publish(1, (ulong)i, new[] { new Message("test", "key", i.ToString()) }); } try { subscription = bus.Subscribe(subscriber, "s-0,27|1,AA", (result, state) => { foreach (var m in result.GetMessages()) { int n = Int32.Parse(m.GetString()); cd.Expect(n); } return(TaskAsyncHelper.True); }, 100, null); Assert.True(cd.Wait(TimeSpan.FromSeconds(10))); } finally { if (subscription != null) { subscription.Dispose(); } } } }