public void Listener_must_listen_in() { //arrange var fooLatch = new TestLatch(2); var barLatch = new TestLatch(2); var barCount = new AtomicCounter(0); var broadcast = Sys.ActorOf<BroadcastActor>(); var newListenerProps = Props.Create(() => new ListenerActor(fooLatch, barLatch, barCount)); var a1 = Sys.ActorOf(newListenerProps); var a2 = Sys.ActorOf(newListenerProps); var a3 = Sys.ActorOf(newListenerProps); //act broadcast.Tell(new Listen(a1)); broadcast.Tell(new Listen(a2)); broadcast.Tell(new Listen(a3)); broadcast.Tell(new Deafen(a3)); broadcast.Tell(new WithListeners(a => a.Tell("foo"))); broadcast.Tell("foo"); //assert barLatch.Ready(TestLatch.DefaultTimeout); Assert.Equal(2, barCount.Current); fooLatch.Ready(TestLatch.DefaultTimeout); foreach (var actor in new[] {a1, a2, a3, broadcast}) { Sys.Stop(actor); } }
public void Smallest_mailbox_pool_must_deliver_messages_to_idle_actor() { var usedActors = new ConcurrentDictionary<int, string>(); var router = Sys.ActorOf(new SmallestMailboxPool(3).Props(Props.Create(() => new SmallestMailboxActor(usedActors)))); var busy = new TestLatch(1); var received0 = new TestLatch(1); router.Tell(Tuple.Create(busy, received0)); received0.Ready(TestKitSettings.DefaultTimeout); var received1 = new TestLatch(1); router.Tell(Tuple.Create(1, received1)); received1.Ready(TestKitSettings.DefaultTimeout); var received2 = new TestLatch(1); router.Tell(Tuple.Create(2, received2)); received2.Ready(TestKitSettings.DefaultTimeout); var received3 = new TestLatch(1); router.Tell(Tuple.Create(3, received3)); received3.Ready(TestKitSettings.DefaultTimeout); busy.CountDown(); var busyPath = usedActors[0]; busyPath.Should().NotBeNull(); var path1 = usedActors[1]; var path2 = usedActors[2]; var path3 = usedActors[3]; path1.Should().NotBeNull(busyPath); path2.Should().NotBeNull(busyPath); path3.Should().NotBeNull(busyPath); }
public void GetTimeout() { var timeoutLatch = new TestLatch(); var timeoutActor = Sys.ActorOf(Props.Create(() => new TimeoutActor(timeoutLatch))); timeoutLatch.Ready(TestLatch.DefaultTimeout); Sys.Stop(timeoutActor); }
public void Props_must_create_actor_by_producer() { TestLatch latchProducer = new TestLatch(Sys); TestLatch latchActor = new TestLatch(Sys); var props = Props.CreateBy<TestProducer>(latchProducer, latchActor); ActorRef actor = Sys.ActorOf(props); latchActor.Ready(TimeSpan.FromSeconds(1)); }
public void RescheduleTimeout() { var timeoutLatch = new TestLatch(Sys); var timeoutActor = Sys.ActorOf(Props.Create(() => new TimeoutActor(timeoutLatch))); timeoutActor.Tell(Tick); timeoutLatch.Ready(TestLatch.DefaultTimeout); Sys.Stop(timeoutActor); }
public void BroadcastGroup_router_must_broadcast_message_using_Tell() { var doneLatch = new TestLatch(2); var counter1 = new AtomicCounter(0); var counter2 = new AtomicCounter(0); var actor1 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter1))); var actor2 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter2))); var routedActor = Sys.ActorOf(Props.Create<TestActor>().WithRouter(new BroadcastGroup(actor1.Path.ToString(), actor2.Path.ToString()))); routedActor.Tell(new Broadcast(1)); routedActor.Tell(new Broadcast("end")); doneLatch.Ready(TimeSpan.FromSeconds(1)); counter1.Current.ShouldBe(1); counter2.Current.ShouldBe(1); }
public void Scatter_gather_router_must_deliver_a_broadcast_message_using_tell() { var doneLatch = new TestLatch(sys, 2); var counter1 = new AtomicInteger(0); var counter2 = new AtomicInteger(0); var actor1 = sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter1))); var actor2 = sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter2))); var routedActor = sys.ActorOf(Props.Create<TestActor>().WithRouter(new ScatterGatherFirstCompletedGroup(TimeSpan.FromSeconds(1), actor1.Path.ToString(), actor2.Path.ToString()))); routedActor.Tell(new Broadcast(1)); routedActor.Tell(new Broadcast("end")); doneLatch.Ready(TimeSpan.FromSeconds(1)); counter1.Value.ShouldBe(1); counter2.Value.ShouldBe(1); }
public void BroadcastGroup_router_must_broadcast_message_using_Ask() { var doneLatch = new TestLatch(2); var counter1 = new AtomicCounter(0); var actor1 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter1))); var counter2 = new AtomicCounter(0); var actor2 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter2))); var paths = new List<string> { actor1.Path.ToString(), actor2.Path.ToString() }; var routedActor = Sys.ActorOf(new BroadcastGroup(paths).Props()); routedActor.Ask(new Broadcast(1)); routedActor.Tell(new Broadcast("end")); doneLatch.Ready(RemainingOrDefault); counter1.Current.Should().Be(1); counter2.Current.Should().Be(1); }
public void Random_must_be_able_to_shut_down_its_instance() { const int routeeCount = 7; var testLatch = new TestLatch(Sys, routeeCount); var router = Sys.ActorOf(new RandomPool(routeeCount).Props(Props.Create(() => new HelloWorldActor(testLatch)))); router.Tell("hello", TestActor); router.Tell("hello", TestActor); router.Tell("hello", TestActor); router.Tell("hello", TestActor); router.Tell("hello", TestActor); Within(TimeSpan.FromSeconds(2), () => { ExpectMsg("world"); ExpectMsg("world"); ExpectMsg("world"); ExpectMsg("world"); ExpectMsg("world"); return true; }); Sys.Stop(router); testLatch.Ready(TimeSpan.FromSeconds(5)); }
public void Smallest_mailbox_router_must_deliver_messages_to_idle_actor() { var usedActors = new ConcurrentDictionary<int, string>(); var router = Sys.ActorOf(new SmallestMailboxPool(3).Props(Props.Create(() => new SmallestMailboxActor(usedActors)))); var busy = new TestLatch(1); var received0 = new TestLatch(1); router.Tell(Tuple.Create(busy, received0)); received0.Ready(TestLatch.DefaultTimeout); var received1 = new TestLatch(1); router.Tell(Tuple.Create(1, received1)); received1.Ready(TestLatch.DefaultTimeout); var received2 = new TestLatch(1); router.Tell(Tuple.Create(2, received2)); received2.Ready(TestLatch.DefaultTimeout); var received3 = new TestLatch(1); router.Tell(Tuple.Create(3, received3)); received3.Ready(TestLatch.DefaultTimeout); busy.CountDown(); var busyPath = usedActors[0]; Assert.NotEqual(busyPath, null); Assert.Equal(usedActors.Count, 4); var path1 = usedActors[1]; var path2 = usedActors[2]; var path3 = usedActors[3]; Assert.NotEqual(path1, busyPath); Assert.NotEqual(path2, busyPath); Assert.NotEqual(path3, busyPath); }
public void An_actor_watching_a_remote_actor_in_the_cluster_must_receive_terminated_when_watched_node_becomes_down_removed() { Within(TimeSpan.FromSeconds(30), () => { AwaitClusterUp(_config.First, _config.Second, _config.Third, _config.Fourth); EnterBarrier("cluster-up"); RunOn(() => { EnterBarrier("subjected-started"); var path2 = new RootActorPath(GetAddress(_config.Second)) / "user" / "subject"; var path3 = new RootActorPath(GetAddress(_config.Third)) / "user" / "subject"; var watchEstablished = new TestLatch(2); Sys.ActorOf(Props.Create(() => new Observer(path2, path3, watchEstablished, TestActor)) .WithDeploy(Deploy.Local), "observer1"); watchEstablished.Ready(); EnterBarrier("watch-established"); ExpectMsg(path2); ExpectNoMsg(TimeSpan.FromSeconds(2)); EnterBarrier("second-terminated"); MarkNodeAsUnavailable(GetAddress(_config.Third)); AwaitAssert(() => Assert.True(ClusterView.UnreachableMembers.Select(x => x.Address).Contains(GetAddress(_config.Third)))); Cluster.Down(GetAddress(_config.Third)); //removed AwaitAssert(() => Assert.False(ClusterView.Members.Select(x => x.Address).Contains(GetAddress(_config.Third)))); AwaitAssert(() => Assert.False(ClusterView.UnreachableMembers.Select(x => x.Address).Contains(GetAddress(_config.Third)))); ExpectMsg(path3); EnterBarrier("third-terminated"); }, _config.First); RunOn(() => { Sys.ActorOf(BlackHoleActor.Props, "subject"); EnterBarrier("subjected-started"); EnterBarrier("watch-established"); RunOn(() => { MarkNodeAsUnavailable(GetAddress(_config.Second)); AwaitAssert(() => Assert.True(ClusterView.UnreachableMembers.Select(x => x.Address).Contains(GetAddress(_config.Second)))); Cluster.Down(GetAddress(_config.Second)); //removed AwaitAssert(() => Assert.False(ClusterView.Members.Select(x => x.Address).Contains(GetAddress(_config.Second)))); AwaitAssert(() => Assert.False(ClusterView.UnreachableMembers.Select(x => x.Address).Contains(GetAddress(_config.Second)))); }, _config.Third); EnterBarrier("second-terminated"); EnterBarrier("third-terminated"); }, _config.Second, _config.Third, _config.Fourth); RunOn(() => { EnterBarrier("subjected-started"); EnterBarrier("watch-established"); EnterBarrier("second-terminated"); EnterBarrier("third-terminated"); }, _config.Fifth); EnterBarrier("after-1"); }); }
public void DefaultResizer_must_be_possible_to_define_in_configuration() { var latch = new TestLatch(Sys, 3); var router = Sys.ActorOf(Props.Create<ResizerTestActor>().WithRouter(new FromConfig()), "router1"); router.Tell(latch); router.Tell(latch); router.Tell(latch); latch.Ready(TestKitSettings.DefaultTimeout); //messagesPerResize is 10 so there is no risk of additional resize (RouteeSize(router)).ShouldBe(2); }
public void DefaultResizer_must_be_possible_to_define_programmatically() { var latch = new TestLatch(Sys, 3); var resizer = new DefaultResizer(2, 3); var router = Sys.ActorOf(Props.Create<ResizerTestActor>().WithRouter(new RoundRobinPool(0, resizer))); router.Tell(latch); router.Tell(latch); router.Tell(latch); latch.Ready(TestKitSettings.DefaultTimeout); //messagesPerResize is 10 so there is no risk of additional resize (RouteeSize(router)).ShouldBe(2); }
public void Set_of_connected_cluster_systems_must_when_two_nodes_after_cluster_convergence_updates_membership_table_then_all_MembershipChangeListeners_should_be_triggered() { AwaitClusterUp(_config.First); RunOn(() => { var latch = new TestLatch(); var expectedAddresses = ImmutableList.Create(GetAddress(_config.First), GetAddress(_config.Second)); var listener = Sys.ActorOf(Props.Create(() => new Listener(latch, expectedAddresses)).WithDeploy(Deploy.Local)); Cluster.Subscribe(listener, new[] { typeof(ClusterEvent.IMemberEvent) }); EnterBarrier("listener-1-registered"); Cluster.Join(GetAddress(_config.First)); latch.Ready(); }, _config.First, _config.Second); RunOn(() => { EnterBarrier("listener-1-registered"); }, _config.Third); EnterBarrier("after-1"); }
public void A_Flow_with_SelectAsyncUnordered_must_signal_error_from_SelectAsyncUnordered() { this.AssertAllStagesStopped(() => { var latch = new TestLatch(1); var c = this.CreateManualSubscriberProbe<int>(); Source.From(Enumerable.Range(1, 5)) .SelectAsyncUnordered(4, n => { if (n == 3) throw new TestException("err2"); return Task.Run(() => { latch.Ready(TimeSpan.FromSeconds(10)); return n; }); }) .RunWith(Sink.FromSubscriber(c), Materializer); var sub = c.ExpectSubscription(); sub.Request(10); c.ExpectError().Message.Should().Be("err2"); latch.CountDown(); }, Materializer); }
public void A_Flow_with_SelectAsync_must_signal_task_failure() { this.AssertAllStagesStopped(() => { var latch = new TestLatch(1); var c = TestSubscriber.CreateManualProbe<int>(this); Source.From(Enumerable.Range(1, 5)) .SelectAsync(4, n => Task.Run(() => { if (n == 3) throw new TestException("err1"); latch.Ready(TimeSpan.FromSeconds(10)); return n; })) .To(Sink.FromSubscriber(c)).Run(Materializer); var sub = c.ExpectSubscription(); sub.Request(10); c.ExpectError().InnerException.Message.Should().Be("err1"); latch.CountDown(); }, Materializer); }
public async Task Round_robin_pool_must_deliver_messages_in_a_round_robin_fashion() { const int connectionCount = 10; const int iterationCount = 10; var doneLatch = new TestLatch(connectionCount); var counter = new AtomicCounter(0); var replies = new Dictionary<int, int>(); for (int i = 0; i < connectionCount; i++) { replies[i] = 0; } var actor = Sys.ActorOf(new RoundRobinPool(connectionCount) .Props(Props.Create(() => new RoundRobinPoolActor(doneLatch, counter))), "round-robin"); for (int i = 0; i < iterationCount; i++) { for (int k = 0; k < connectionCount; k++) { int id = await actor.Ask<int>("hit"); replies[id] = replies[id] + 1; } } counter.Current.Should().Be(connectionCount); actor.Tell(new Broadcast("end")); doneLatch.Ready(5.Seconds()); replies.Values.ForEach(c => c.Should().Be(iterationCount)); }
public void An_ActorRef_should_suppport_reply_via_Sender() { var latch = new TestLatch(Sys, 4); var serverRef = Sys.ActorOf(Props.Create<ReplyActor>()); var clientRef = Sys.ActorOf(Props.Create(() => new SenderActor(serverRef, latch))); clientRef.Tell("complex"); clientRef.Tell("simple"); clientRef.Tell("simple"); clientRef.Tell("simple"); latch.Ready(TimeSpan.FromSeconds(3)); latch.Reset(); clientRef.Tell("complex2"); clientRef.Tell("simple"); clientRef.Tell("simple"); clientRef.Tell("simple"); latch.Ready(TimeSpan.FromSeconds(3)); Sys.Stop(clientRef); Sys.Stop(serverRef); }
public void Registered_MembershipChangeListener_must_be_notified_when_new_node_is_exiting() { AwaitClusterUp(_config.First, _config.Second, _config.Third); RunOn(() => { EnterBarrier("registered-listener"); Cluster.Leave(GetAddress(_config.Second)); }, _config.First); RunOn(() => { var exitingLatch = new TestLatch(); var removedLatch = new TestLatch(); var secondAddress = GetAddress(_config.Second); var watcher = Sys.ActorOf(Props.Create(() => new Watcher(exitingLatch, removedLatch, secondAddress)) .WithDeploy(Deploy.Local)); Cluster.Subscribe(watcher, new[] { typeof(ClusterEvent.IMemberEvent) }); EnterBarrier("registered-listener"); exitingLatch.Ready(); removedLatch.Ready(); }, _config.Second); RunOn(() => { var exitingLatch = new TestLatch(); var secondAddress = GetAddress(_config.Second); var watcher = Sys.ActorOf(Props.Create(() => new Watcher(exitingLatch, null, secondAddress)) .WithDeploy(Deploy.Local)); Cluster.Subscribe(watcher, new[] { typeof(ClusterEvent.IMemberEvent) }); EnterBarrier("registered-listener"); exitingLatch.Ready(); }, _config.Third); EnterBarrier("finished"); }
public void Conflate_must_restart_when_seed_throws_and_a_RestartDescider_is_used() { var sourceProbe = this.CreatePublisherProbe<int>(); var sinkProbe = this.CreateManualSubscriberProbe<int>(); var exceptionlath = new TestLatch(); var graph = Source.FromPublisher(sourceProbe).ConflateWithSeed(i => { if (i%2 == 0) { exceptionlath.Open(); throw new TestException("I hate even seed numbers"); } return i; }, (sum, i) => sum + i) .WithAttributes(ActorAttributes.CreateSupervisionStrategy(Deciders.RestartingDecider)) .To(Sink.FromSubscriber(sinkProbe)) .WithAttributes(Attributes.CreateInputBuffer(1, 1)); RunnableGraph.FromGraph(graph).Run(Materializer); var sub = sourceProbe.ExpectSubscription(); var sinkSub = sinkProbe.ExpectSubscription(); // push the first value sub.ExpectRequest(1); sub.SendNext(1); // and consume it, so that the next element // will trigger seed sinkSub.Request(1); sinkProbe.ExpectNext(1); sub.ExpectRequest(1); sub.SendNext(2); // make sure the seed exception happened // before going any further exceptionlath.Ready(TimeSpan.FromSeconds(3)); sub.ExpectRequest(1); sub.SendNext(3); // now we should have lost the 2 and the accumulated state sinkSub.Request(1); sinkProbe.ExpectNext(3); }
public async Task Round_robin_group_must_deliver_messages_in_a_round_robin_fashion() { const int connectionCount = 10; const int iterationCount = 10; var doneLatch = new TestLatch(connectionCount); var replies = new Dictionary<string, int>(); for (int i = 1; i <= connectionCount; i++) { replies["target-" + i] = 0; } var paths = Enumerable.Range(1, connectionCount).Select(n => { var routee = Sys.ActorOf(Props.Create(() => new RoundRobinGroupActor(doneLatch)), "target-" + n); return routee.Path.ToStringWithoutAddress(); }); var actor = Sys.ActorOf(new RoundRobinGroup(paths).Props(), "round-robin-group1"); for (int i = 0; i < iterationCount; i++) { for (int k = 0; k < connectionCount; k++) { string id = await actor.Ask<string>("hit"); replies[id] = replies[id] + 1; } } actor.Tell(new Broadcast("end")); doneLatch.Ready(5.Seconds()); replies.Values.ForEach(c => c.Should().Be(iterationCount)); }
public void Round_robin_pool_must_deliver_deliver_a_broadcast_message_using_Tell() { const int routeeCount = 5; var helloLatch = new TestLatch(routeeCount); var stopLatch = new TestLatch(routeeCount); var actor = Sys.ActorOf(new RandomPool(routeeCount) .Props(Props.Create(() => new RoundRobinPoolBroadcastActor(helloLatch, stopLatch))), "round-robin-broadcast"); actor.Tell(new Broadcast("hello")); helloLatch.Ready(5.Seconds()); Sys.Stop(actor); stopLatch.Ready(5.Seconds()); }
public void Random_pool_must_be_able_to_shut_down_its_instance() { const int routeeCount = 7; var testLatch = new TestLatch(routeeCount); var actor = Sys.ActorOf(new RandomPool(routeeCount) .Props(Props.Create(() => new HelloWorldActor(testLatch))), "random-shutdown"); actor.Tell("hello"); actor.Tell("hello"); actor.Tell("hello"); actor.Tell("hello"); actor.Tell("hello"); Within(TimeSpan.FromSeconds(2), () => { for (int i = 1; i <= 5; i++) { ExpectMsg("world"); } }); Sys.Stop(actor); testLatch.Ready(5.Seconds()); }
ALeaderThatIsLeavingMustBeMovedToLeavingThenExitingThenRemovedThenBeShutDownAndThenANewLeaderShouldBeElected () { AwaitClusterUp(_config.First, _config.Second, _config.Third); var oldLeaderAddress = ClusterView.Leader; Within(TimeSpan.FromSeconds(30), () => { if (ClusterView.IsLeader) { EnterBarrier("registered-listener"); Cluster.Leave(oldLeaderAddress); EnterBarrier("leader-left"); // verify that the LEADER is shut down AwaitCondition(() => Cluster.IsTerminated); EnterBarrier("leader-shutdown"); } else { var exitingLatch = new TestLatch(); var listener = Sys.ActorOf(Props.Create(() => new Listener(oldLeaderAddress, exitingLatch)).WithDeploy(Deploy.Local)); Cluster.Subscribe(listener, new []{typeof(ClusterEvent.IMemberEvent)}); EnterBarrier("registered-listener"); EnterBarrier("leader-left"); // verify that the LEADER is EXITING exitingLatch.Ready(TestLatch.DefaultTimeout); EnterBarrier("leader-shutdown"); MarkNodeAsUnavailable(oldLeaderAddress); // verify that the LEADER is no longer part of the 'members' set AwaitAssert(() => ClusterView.Members.Select(m => m.Address).Contains(oldLeaderAddress).ShouldBeFalse()); // verify that the LEADER is not part of the 'unreachable' set AwaitAssert(() => ClusterView.UnreachableMembers.Select(m => m.Address).Contains(oldLeaderAddress).ShouldBeFalse()); // verify that we have a new LEADER AwaitAssert(() => ClusterView.Leader.ShouldNotBe(oldLeaderAddress)); } EnterBarrier("finished"); }); }
public void NotGetTimeout() { var timeoutLatch = new TestLatch(); var timeoutActor = Sys.ActorOf(Props.Create(() => new NoTimeoutActor(timeoutLatch))); Assert.Throws<TimeoutException>(() => timeoutLatch.Ready(TestLatch.DefaultTimeout)); Sys.Stop(timeoutActor); }
public void Round_robin_pool_must_be_able_to_shut_down_its_instance() { const int routeeCount = 5; var helloLatch = new TestLatch(routeeCount); var stopLatch = new TestLatch(routeeCount); var actor = Sys.ActorOf(new RoundRobinPool(routeeCount) .Props(Props.Create(() => new HelloWorldPoolActor(helloLatch, stopLatch)))); actor.Tell("hello", TestActor); actor.Tell("hello", TestActor); actor.Tell("hello", TestActor); actor.Tell("hello", TestActor); actor.Tell("hello", TestActor); helloLatch.Ready(5.Seconds()); Sys.Stop(actor); stopLatch.Ready(5.Seconds()); }
public void Conflate_must_restart_when_aggregate_throws_and_a_RestartingDecider_is_used() { var sourceProbe = this.CreatePublisherProbe<string>(); var sinkProbe = this.CreateSubscriberProbe<string>(); var latch = new TestLatch(); var conflate = Flow.Create<string>().ConflateWithSeed(i => i, (state, elem) => { if (elem == "two") { latch.Open(); throw new TestException("two is a three letter word"); } return state + elem; }).WithAttributes(ActorAttributes.CreateSupervisionStrategy(Deciders.RestartingDecider)); var graph = Source.FromPublisher(sourceProbe) .Via(conflate) .To(Sink.FromSubscriber(sinkProbe)) .WithAttributes(Attributes.CreateInputBuffer(4, 4)); RunnableGraph.FromGraph(graph).Run(Materializer); var sub = sourceProbe.ExpectSubscription(); sub.ExpectRequest(4); sub.SendNext("one"); sub.SendNext("two"); sub.SendNext("three"); sub.SendComplete(); //"one" should be lost latch.Ready(TimeSpan.FromSeconds(3)); sinkProbe.RequestNext("three"); }
public void Tail_chopping_group_router_must_deliver_a_broadcast_message_using_tell() { var doneLatch = new TestLatch(2); var counter1 = new AtomicCounter(0); var actor1 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter1))); var counter2 = new AtomicCounter(0); var actor2 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter2))); var paths = new List<string> { actor1.Path.ToString(), actor2.Path.ToString() }; var routedActor = Sys.ActorOf(new TailChoppingGroup(paths, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(100)).Props()); routedActor.Tell(new Broadcast(1)); routedActor.Tell(new Broadcast("end")); doneLatch.Ready(TestKitSettings.DefaultTimeout); counter1.Current.Should().Be(1); counter2.Current.Should().Be(1); }
public void Tail_chopping_router_must_deliver_a_broadcast_message_using_tell() { var doneLatch = new TestLatch(2); var counter1 = new AtomicCounter(0); var counter2 = new AtomicCounter(0); var actor1 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter1)), "Actor1"); var actor2 = Sys.ActorOf(Props.Create(() => new BroadcastTarget(doneLatch, counter2)), "Actor2"); var routedActor = Sys.ActorOf(Props.Create<TestActor>() .WithRouter(new TailChoppingGroup(new[] { actor1.Path.ToString(), actor2.Path.ToString() }, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(100)) )); routedActor.Tell(new Broadcast(1)); routedActor.Tell(new Broadcast("end")); doneLatch.Ready(TimeSpan.FromSeconds(1)); counter1.Current.ShouldBe(1); counter2.Current.ShouldBe(1); }
public void Conflate_must_restart_when_aggregate_throws_and_a_ResumingDecider_is_used() { var sourceProbe = this.CreatePublisherProbe<int>(); var sinkProbe = this.CreateManualSubscriberProbe<List<int>>(); var saw4Latch = new TestLatch(); var graph = Source.FromPublisher(sourceProbe).ConflateWithSeed(i => new List<int> { i }, (state, elem) => { if (elem == 2) throw new TestException("three is a four letter word"); if (elem == 4) saw4Latch.Open(); state.Add(elem); return state; }) .WithAttributes(ActorAttributes.CreateSupervisionStrategy(Deciders.ResumingDecider)) .To(Sink.FromSubscriber(sinkProbe)) .WithAttributes(Attributes.CreateInputBuffer(1, 1)); RunnableGraph.FromGraph(graph).Run(Materializer); var sub = sourceProbe.ExpectSubscription(); var sinkSub = sinkProbe.ExpectSubscription(); // push the first three values, the third will trigger // the exception sub.ExpectRequest(1); sub.SendNext(1); // causing the 1 to get thrown away sub.ExpectRequest(1); sub.SendNext(2); sub.ExpectRequest(1); sub.SendNext(3); sub.ExpectRequest(1); sub.SendNext(4); // and consume it, so that the next element // will trigger seed saw4Latch.Ready(TimeSpan.FromSeconds(3)); sinkSub.Request(1); sinkProbe.ExpectNext().ShouldAllBeEquivalentTo(new [] {1, 3, 4}); }