// same as previous but should not deliver the message // because the second subscriber has also the same filter public async Task Test_DeliverAtLeastOnce_Delayed2() { var hub = new MetaPubSub(); bool timeoutException = false; // first subscriber which will not process the message due to its filter hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); // second subscriber which will subscribe after the message has been published var t = Task.Run(async() => { await Task.Delay(50); hub.Subscribe <MyMessage>(OnMyMessageHandler2, OnMyMessagePredicate); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler2); }); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 100 }; try { // the message has a timeout and can wait until the second subscriber come await hub.Publish(message); } catch (TimeoutException) { timeoutException = true; } Assert.IsTrue(timeoutException); Assert.IsTrue(message.DeliveredCount == 0); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// subscribed twice but delivered only once public async Task Basic() { var hub = new MetaPubSub(); await Task.Run(() => { for (int i = 0; i < 10_000; i++) { var subscriber = new MySubscriber(); //await Task.Delay(50); hub.Subscribe <MyMessage>(subscriber.Handler); } }); int totalDeliveryCount1 = 0; var t1 = Task.Run(async() => { for (int i = 0; i < 1000; i++) { var subscriber = new MySubscriber(); hub.Subscribe <MyEvent>(subscriber.Handler); var message = new MyMessage(); await hub.Publish(message); totalDeliveryCount1 += message.DeliveredCount; await hub.Unsubscribe <MyEvent>(subscriber.Handler); } }); int totalDeliveryCount2 = 0; var t2 = Task.Run(async() => { for (int i = 0; i < 1000; i++) { var subscriber = new MySubscriber(); hub.Subscribe <MyMessage>(subscriber.Handler); var message = new MyMessage(); await hub.Publish(message); totalDeliveryCount2 += message.DeliveredCount; await hub.Unsubscribe <MyMessage>(subscriber.Handler); } }); await Task.WhenAll(t1, t2); Assert.IsTrue(totalDeliveryCount1 > (10_000 * 1000) && totalDeliveryCount1 < (10_000 * 1000 + 1000)); Assert.IsTrue(totalDeliveryCount2 == 10_000 * 1000 + 1000); }
// Should deliver if message is filtered at first and DeliverAtLeastOnce = true but Timeout > 0 and // after the message has published a new subscriber arrived public async Task Test_DeliverAtLeastOnce_Delayed() { var hub = new MetaPubSub(); // first subscriber which will not process the message due to its filter hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); // second subscriber which will subscribe after the message has been published // also with filter, will not process the message var t = Task.Run(async() => { await Task.Delay(50); hub.Subscribe <MyMessage>(OnMyMessageHandler2, OnMyMessagePredicate); }); // third subscriber which will subscribe after the message has been published var t2 = Task.Run(async() => { await Task.Delay(70); hub.Subscribe <MyMessage>(OnMyMessageHandler3); }); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 200000 }; // the message has a timeout and can wait until the second subscriber come await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); //hub.Unsubscribe<MyMessage>(OnMyMessageHandler2); //hub.Unsubscribe<MyMessage>(OnMyMessageHandler3); }
// timeout to wait for a subscriber - your message can be queued and wait until someone subscribed and processed it public async Task DeliverAtLeastOnceDelayedExample() { var hub = new MetaPubSub(); // a subscriber that will subscribe after the message has been published var t = Task.Run(async() => { await Task.Delay(1500); Console.WriteLine($"Subscribed to MyMessage at {DateTime.Now:HH:mm:ss.fff}"); hub.Subscribe <MyMessage>(OnMyMessage); }); // the message has the 10 seconds timeout and can wait until the subscriber come var message = new MyMessage { DeliverAtLeastOnce = true, // this must be set to true WaitForSubscriberTimeout = 10_000 }; Console.WriteLine($"Start publishing and awaiting at {DateTime.Now:HH:mm:ss.fff}"); // this method will wait until the subscriber receives the message or until timeout expired (10 seconds) await hub.Publish(message); Console.WriteLine($"End awaiting at {DateTime.Now:HH:mm:ss.fff}"); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// at least once delivery check async Task AtLeastOnceDeliveryExample() { var hub = new MetaPubSub(); var message = new MyMessage { // if this not set, NoSubscribersException will not be thrown DeliverAtLeastOnce = true }; try { // publishing a message when no one is subscribed await hub.Publish(message); } catch (NoSubscribersException ex) { // no one is listening Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } hub.Subscribe <MyMessage>(OnMyMessage); await hub.Publish(message); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// subscribes on server and receives a message public async Task SendMessageToClient() { var pipeName = Guid.NewGuid().ToString(); var clientConnectedEvent = new ManualResetEventSlim(); var @event = new ManualResetEventSlim(); int recvCount = 0; Task Handler(MyMessage x) { if (++recvCount == 10) { @event.Set(); } return(Task.CompletedTask); } // creating remote hub var t = Task.Run(async() => { var hub = new MetaPubSub(); hub.StartServer(pipeName); // wait for the subscriber clientConnectedEvent.Wait(5000); // publishing a message at the remote hub for (int i = 0; i < 10; i++) { await hub.Publish(new MyMessage()); } }); // local hub creation var hub = new MetaPubSub(); await hub.ConnectToServer(pipeName); await hub.SubscribeOnServer <MyMessage>(Handler); // delay allowing the server to process the subscription request await Task.Delay(100); clientConnectedEvent.Set(); @event.Wait(5000); // unsubscribing await hub.Unsubscribe <MyMessage>(Handler); Assert.IsTrue(@event.IsSet && recvCount == 10); }
async Task BasicExample() { // hub creation var hub = new MetaPubSub(); // subscribing to MyMessage hub.Subscribe <MyMessage>(OnMyMessage); // publishing a message await hub.Publish(new MyMessage()); // unsubscribing await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// exceptions handling - all exceptions raised when a message processing by subscribers can be caught by the publisher as an AggregateException async Task ExceptionHandlingExample() { var hub = new MetaPubSub(); try { var message = new MyMessage { DeliverAtLeastOnce = true, }; // publishing a message when no one subscribed - NoSubscribersException //await hub.Publish(message); // publishing a message when no one subscribed and Timeout > 0 - TimeoutException //message.Timeout = 100; //await hub.Publish(message); hub.Subscribe <MyMessage>(OnMyMessageHandlerWithException); // publishing a message await hub.Publish(message); } catch (NoSubscribersException ex) { // No one is subscribed to this message and (message.DeliverAtLeastOnce == true and message.Timeout == 0) Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } catch (TimeoutException ex) { // No one is subscribed to this message and (message.DeliverAtLeastOnce == true and message.Timeout > 0) Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } catch (AggregateException ex) { // All exceptions raised when a message processing by subscribers // can be caught by the publisher as an AggregateException. // If some of the subscribers throw an exception, other subscribers // continues to process the message. Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); foreach (var innerEx in ex.InnerExceptions) { Console.WriteLine($"\tInner Exception {innerEx.GetType()}: {innerEx.Message}"); } } await hub.Unsubscribe <MyMessage>(OnMyMessageHandlerWithException); }
async Task BasicExample() { int count = 0; Task Handler(MyMessage x) { count++; return(Task.CompletedTask); } // Creating the server hub. // The server and the client hubs should be created in separate processes, // this example is for demo only. var serverHub = new MetaPubSub(); // Starting the hub as a server named 'Meta'. serverHub.StartServer("Meta"); // Client hub creation. There are can be several hubs connected to the same server. var clientHub = new MetaPubSub(); // Connecting to the remote server. await clientHub.ConnectToServer("Meta"); // Subscribing to MyMessage on the server and locally at the same time. await clientHub.SubscribeOnServer <MyMessage>(Handler); // The server publishes a message. await serverHub.Publish(new MyMessage()); // Client hub publishes a message and it will be received locally without being sent to the server. await clientHub.Publish(new MyMessage()); // Client hub sends a message to the server where it will be published and sent back. await clientHub.PublishOnServer(new MyMessage()); // All three messages should be received. Debug.Assert(count == 3); // Unsubscribing both on the server-side and locally. await clientHub.Unsubscribe <MyMessage>(Handler); }
public async Task Predicate() { var hub = new MetaPubSub(); hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info }; await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Error }; await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// scheduling a message - your message can be queued and published after a time delay public async Task ScheduleExample() { var hub = new MetaPubSub(); hub.Subscribe <MyMessage>(OnMyMessage); var message = new MyMessage { DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 1500 }; // The message will be published after 3 seconds delay and after that, it can wait another 500 ms for a subscriber. // When using Schedule method there is no way to receive NoSubscriberException or AggregateException. hub.Schedule(message, millisecondsDelay: 3000); Console.WriteLine($"Message scheduled at {DateTime.Now:HH:mm:ss.fff}, delay - 3 sec"); // waiting before unsubscribing await Task.Delay(3500); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// Should get the NoSubscribersException if message is filtered and DeliverAtLeastOnce = true public async Task Test_DeliverAtLeastOnce_Filtered() { var hub = new MetaPubSub(); bool noSubscriberException = false; hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true }; try { await hub.Publish(message); } catch (NoSubscribersException) { noSubscriberException = true; } Assert.IsTrue(noSubscriberException); Assert.IsTrue(message.DeliveredCount == 0); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// subscribed twice but delivered only once public async Task Basic() { var hub = new MetaPubSub(); var message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); hub.Subscribe <MyMessage>(OnMyMessageHandler); hub.Subscribe <MyMessage>(OnMyMessageHandler); message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); }