public void BroadcastHub_must_send_the_same_elements_to_consumers_attaching_around_the_same_time() { this.AssertAllStagesStopped(() => { var other = Source.From(Enumerable.Range(2, 9)) .MapMaterializedValue <TaskCompletionSource <int> >(_ => null); var t = Source.Maybe <int>() .Concat(other) .ToMaterialized(BroadcastHub.Sink <int>(8), Keep.Both) .Run(Materializer); var firstElement = t.Item1; var source = t.Item2; var f1 = source.RunWith(Sink.Seq <int>(), Materializer); var f2 = source.RunWith(Sink.Seq <int>(), Materializer); // Ensure subscription of Sinks. This is racy but there is no event we can hook into here. Thread.Sleep(500); firstElement.SetResult(1); f1.AwaitResult().ShouldAllBeEquivalentTo(Enumerable.Range(1, 10)); f2.AwaitResult().ShouldAllBeEquivalentTo(Enumerable.Range(1, 10)); }, Materializer); }
public void PublishSubscribeOnHubsAddsAndRemovesPublishersAndSubscribers() { const int publisherMaxCount = 16; const int subscriberMaxCount = 16; const int bufferSize = 4; // Source ToMat Bidi // +------------+ +------------+ // | MergeHub | |BroadcastHub| // | Source | ~> Message ~> | Sink | // | | | | // +------------+ +------------+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~ (Sink<Message>, Source<Message>) ~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Sink <string, NotUsed> mergeSink, Source <string, NotUsed> mergeSource) = MergeHub.Source <string>(perProducerBufferSize: publisherMaxCount) .ToMaterialized(BroadcastHub.Sink <string>(bufferSize: subscriberMaxCount), Keep.Both) .Run(_materializer); TestProbe sub0 = CreateTestProbe(); TestProbe sub1 = CreateTestProbe(); // Flow JoinMat Bidi // +------------+ +------------+ // | FromSink | ~> Message ~> |KillSwitches| ~> Message // | And | | Single | // | Source | <~ Message <~ | Bidi | <~ Message // +------------+ +------------+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~ UniqueKillSwitch ~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Flow <string, string, UniqueKillSwitch> busFlow = Flow.FromSinkAndSource(mergeSink, mergeSource) .JoinMaterialized(KillSwitches.SingleBidi <string, string>(), Keep.Right); var(pub0, uniqueKillSwitch0) = Source.ActorRef <string>(bufferSize, OverflowStrategy.Fail) .ViaMaterialized(busFlow, Keep.Both) .To(Sink.ActorRef <string>(sub0, "complete")) .Run(_materializer); pub0.Tell("It's chat member 0!"); sub0.ExpectMsg("It's chat member 0!"); // Echo. sub0.ExpectNoMsg(TimeSpan.FromMilliseconds(50)); var(pub1, uniqueKillSwitch1) = Source.ActorRef <string>(bufferSize, OverflowStrategy.Fail) .ViaMaterialized(busFlow, Keep.Both) .To(Sink.ActorRef <string>(sub1, "complete")) .Run(_materializer); pub1.Tell("Hi! It's chat member 1!"); sub1.ExpectMsg("Hi! It's chat member 1!"); // Echo. sub0.ExpectMsg("Hi! It's chat member 1!"); pub0.Tell("Oh, Hi! Sry, but I gotta go, bye!"); sub0.ExpectMsg("Oh, Hi! Sry, but I gotta go, bye!"); // Echo. uniqueKillSwitch0.Shutdown(); // Looks like this Shutdown is non-blocking. sub0.ExpectMsg("complete", TimeSpan.FromMilliseconds(1000)); // Wait for the running graph to stop. sub1.ExpectMsg("Oh, Hi! Sry, but I gotta go, bye!"); pub1.Tell("Oh, looks like I stayed alone."); sub1.ExpectMsg("Oh, looks like I stayed alone."); // Echo. sub0.ExpectNoMsg(); }