public void RetryConcat_tolerate_killswitch_terminations_inside_the_flow_after_start() { var innerFlow = RetryFlow <int>().ViaMaterialized(KillSwitches.Single <Tuple <Result <int>, int> >(), Keep.Right); var t = this.SourceProbe <int>() .Select(i => Tuple.Create(i, i * i)) .ViaMaterialized(Retry.Concat(100, innerFlow, x => { if (x % 4 == 0) { return new[] { Tuple.Create(x / 2, x / 4) } } ; var sqrt = (int)Math.Sqrt(x); return(new[] { Tuple.Create(sqrt, x) }); }), Keep.Both) .ToMaterialized(this.SinkProbe <Tuple <Result <int>, int> >(), Keep.Both) .Run(Sys.Materializer()); var source = t.Item1.Item1; var killSwitch = t.Item1.Item2; var sink = t.Item2; sink.Request(99); source.SendNext(1); sink.ExpectNext().Item1.Value.Should().Be(2); source.SendNext(2); sink.ExpectNext().Item1.Value.Should().Be(2); killSwitch.Abort(FailedElement.Exception); sink.ExpectError().InnerException.Should().Be(FailedElement.Exception); }
public void Restart_stages_should_demonstrate_a_restart_with_backoff_source() { #region restart-with-backoff-source var httpClient = new HttpClient(); var restartSource = RestartSource.WithBackoff(() => { // Create a source from a task return(Source.FromTask( httpClient.GetAsync("http://example.com/eventstream") // Make a single request ) .Select(c => c.Content.ReadAsStringAsync()) .Select(c => c.Result)); }, minBackoff: TimeSpan.FromSeconds(3), maxBackoff: TimeSpan.FromSeconds(30), randomFactor: 0.2 // adds 20% "noise" to vary the intervals slightly ); #endregion #region with-kill-switch var killSwitch = restartSource .ViaMaterialized(KillSwitches.Single <string>(), Keep.Right) .ToMaterialized(Sink.ForEach <string>(evt => Console.WriteLine($"Got event: {evt}")), Keep.Left) .Run(Materializer); DoSomethingElse(); killSwitch.Shutdown(); #endregion }
public void A_SharedKillSwitch_must_allow_using_multiple_KillSwitch_in_one_graph() { this.AssertAllStagesStopped(() => { var killSwitch1 = KillSwitches.Shared("switch"); var killSwitch2 = KillSwitches.Shared("switch"); var downstream = RunnableGraph.FromGraph(GraphDsl.Create(this.SinkProbe <int>(), (b, sink) => { var merge = b.Add(new Merge <int>(2)); var source1 = b.Add(Source.Maybe <int>().Via(killSwitch1.Flow <int>())); var source2 = b.Add(Source.Maybe <int>().Via(killSwitch2.Flow <int>())); b.From(source1).Via(merge).To(sink); b.From(source2).To(merge); return(ClosedShape.Instance); })).Run(Materializer); downstream.EnsureSubscription(); downstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); killSwitch1.Shutdown(); downstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); killSwitch2.Shutdown(); downstream.ExpectComplete(); }, Materializer); }
public void Shared_kill_switch_must_control_graph_completion_with_shutdown() { #region shared-shutdown var countingSrc = Source.From(Enumerable.Range(1, int.MaxValue)).Delay(1.Seconds(), DelayOverflowStrategy.Backpressure); var lastSink = Sink.Last <int>(); var sharedKillSwitch = KillSwitches.Shared("my-kill-switch"); var last = countingSrc .Via(sharedKillSwitch.Flow <int>()) .RunWith(lastSink, Materializer); var delayedLast = countingSrc .Delay(1.Seconds(), DelayOverflowStrategy.Backpressure) .Via(sharedKillSwitch.Flow <int>()) .RunWith(lastSink, Materializer); DoSomethingElse(); sharedKillSwitch.Shutdown(); last.Wait(1.Seconds()); last.Result.Should().Be(2); delayedLast.Wait(1.Seconds()); delayedLast.Result.Should().Be(1); #endregion }
public async Task Given_journal_When_starting_projection_stream_Then_sink_receives_all_events() { await Init(); _output.WriteLine(Sys.Settings.ToString()); //generate some data var calculationActor = Sys.ActorOf(Props.Create <CalculatorActor>(), "CalculatorOne"); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1+2-3")); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1-2*3")); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1/2+3")); var eventName = nameof(CalculatorActor.CalculationPerformed); var readJournal = PersistenceQuery.Get(Sys).ReadJournalFor <SqlReadJournal>(SqlReadJournal.Identifier); var sharedKillSwitch = KillSwitches.Shared("test"); var source = readJournal.EventsByTag(eventName, Offset.NoOffset()) .Via(sharedKillSwitch.Flow <EventEnvelope>()); var flow = FunctionTotalUsageFlow.Instance; var sink = Sink.Seq <SequencedFunctionTotalUsage>(); var materializer = Sys.Materializer(); var runTask = source.RunWith(flow.ToMaterialized(sink, Keep.Right), materializer); await Task.Delay(5000); sharedKillSwitch.Shutdown(); var res = await runTask; res.Should().HaveCount(6); }
public void A_SharedKillSwitch_must_ignore_subsequent_aborts_and_shutdowns_after_abort() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var t = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); var testException = new TestException("Abort"); killSwitch.Abort(testException); upstream.ExpectCancellation(); downstream.ExpectError().InnerException.Should().Be(testException); killSwitch.Shutdown(); upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); downstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); killSwitch.Abort(new TestException("Abort_Late")); upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); downstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); }, Materializer); }
public void BroadcastHub_must_be_able_to_implement_a_keep_dropping_if_unsubscribed_policy_with_a_simple_SinkIgnore() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("test-switch"); var source = Source.From(Enumerable.Range(1, int.MaxValue)) .Via(killSwitch.Flow <int>()) .RunWith(BroadcastHub.Sink <int>(8), Materializer); // Now the Hub "drops" elements until we attach a new consumer (Source.ignore consumes as fast as possible) source.RunWith(Sink.Ignore <int>(), Materializer); // Now we attached a subscriber which will block the Sink.ignore to "take away" and drop elements anymore, // turning the BroadcastHub to a normal non-dropping mode var downstream = this.CreateSubscriberProbe <int>(); source.RunWith(Sink.FromSubscriber(downstream), Materializer); downstream.Request(1); var first = downstream.ExpectNext(); for (var i = first + 1; i < first + 11; i++) { downstream.Request(1); downstream.ExpectNext(i); } downstream.Cancel(); killSwitch.Shutdown(); }, Materializer); }
public void A_UniqueKillSwitch_must_work_if_used_multiple_times_in_a_flow() { var t = this.SourceProbe <int>() .ViaMaterialized(KillSwitches.Single <int>(), Keep.Both) //ex is a AggregateException from the Task .Recover(ex => ex.InnerException is TestException ? -1 : Option <int> .None) .ViaMaterialized(KillSwitches.Single <int>(), Keep.Both) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1.Item1.Item1; var killSwitch1 = t.Item1.Item1.Item2; var killSwitch2 = t.Item1.Item2; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); var testException = new TestException("Abort"); killSwitch1.Abort(testException); upstream.ExpectCancellation(); downstream.RequestNext(-1); killSwitch2.Shutdown(); downstream.ExpectComplete(); }
public void A_SharedKillSwitch_must_use_its_name_on_the_flows_it_hands_out() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("MySwitchName"); killSwitch.ToString().Should().Be("KillSwitch(MySwitchName)"); killSwitch.Flow <int>().ToString().Should().Be("Flow(KillSwitch(MySwitchName))"); }, Materializer); }
public IAsyncEnumerator <T> GetAsyncEnumerator(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return(new SinkQueueAsyncEnumerator <T>(_source .Via(cancellationToken.AsFlow <T>(cancelGracefully: true)) .ViaMaterialized(KillSwitches.Single <T>(), Keep.Right) .ToMaterialized(thisSinkQueue, Keep.Both) .Run(_materializer), cancellationToken)); }
public IDisposable CreateSubscription(long?lastProcessedCheckpoint, Action <string, Exception> errorHandler) { _errorHandler = errorHandler; var source = CreateSource(Offset.Sequence(lastProcessedCheckpoint ?? 0)) .Select(ee => (ee.Event as IDomainEvent, ee.Offset)) .Where(de => de.Item1 != null) .Batch(20, de => ImmutableList <(IDomainEvent, Offset)> .Empty.Add(de !), (list, evt) => list.Add(evt !)) .Select(de => { var(domainEvent, offset) = de.Last(); return(new Transaction { Checkpoint = ((Sequence)offset).Value, Id = EventId.New.Value, StreamId = domainEvent.GetIdentity().Value, TimeStampUtc = domainEvent.Timestamp.DateTime, Events = new List <LiquidProjections.EventEnvelope>( de .Select(pair => { var(evt, _) = pair; return new LiquidProjections.EventEnvelope { Body = evt, Headers = evt .Metadata .Select(p => Tuple.Create <string, object>(p.Key, p.Value)) .ToDictionary(t => t.Item1, t => t.Item2) }; })) }); }) .Batch(5, t => ImmutableList <Transaction> .Empty.Add(t), (list, transaction) => list.Add(transaction)) .AlsoTo(Sink.OnComplete <ImmutableList <Transaction> >( () => _isCancel.GetAndSet(true), e => { _isCancel.GetAndSet(true); errorHandler(_exceptionInfo, e); })) .ViaMaterialized(KillSwitches.Single <ImmutableList <Transaction> >(), (_, kill) => kill) .PreMaterialize(_materializer); _cancelable = source.Item1; var sinkQueue = source.Item2.RunWith(Sink.Queue <ImmutableList <Transaction> >() .WithAttributes(new Attributes(new Attributes.InputBuffer(2, 2))), _materializer); _runner = Run(sinkQueue); return(this); }
public void A_SharedKillSwitch_must_pass_through_all_elements_unmodified() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var task = Source.From(Enumerable.Range(1, 100)) .Via(killSwitch.Flow <int>()) .RunWith(Sink.Seq <int>(), Materializer); task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue(); task.Result.ShouldAllBeEquivalentTo(Enumerable.Range(1, 100)); }, Materializer); }
public void A_SharedKillSwitch_should_not_cause_problems_if_switch_is_shutdown_after_flow_completed_normally() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var task = Source.From(Enumerable.Range(1, 10)) .Via(killSwitch.Flow <int>()) .RunWith(Sink.Seq <int>(), Materializer); task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue(); task.Result.ShouldAllBeEquivalentTo(Enumerable.Range(1, 10)); killSwitch.Shutdown(); }, Materializer); }
public void RetryConcat_tolerate_killswitch_terminations_inside_the_flow_on_start() { var t = this.SourceProbe <int>() .ViaMaterialized(KillSwitches.Single <int>(), Keep.Right) .Select(i => Tuple.Create(i, i)) .Via(Retry.Concat(100, RetryFlow <int>(), x => new[] { Tuple.Create(x, x + 1) })) .ToMaterialized(this.SinkProbe <Tuple <Result <int>, int> >(), Keep.Both) .Run(Sys.Materializer()); var killSwitch = t.Item1; var sink = t.Item2; sink.Request(99); killSwitch.Abort(FailedElement.Exception); sink.ExpectError().InnerException.Should().Be(FailedElement.Exception); }
public async Task Given_journal_When_starting_projection_stream_Then_projection_launched_producing_data() { var dep = await Init(); _output.WriteLine(Sys.Settings.ToString()); //generate some data var calculationActor = Sys.ActorOf(Props.Create <CalculatorActor>(), "CalculatorOne"); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1+2-3")); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1-2*3")); calculationActor.Tell(new CalculatorActorProtocol.CalculateExpression("1/2+3")); var eventName = nameof(CalculatorActor.CalculationPerformed); var readJournal = PersistenceQuery.Get(Sys).ReadJournalFor <SqlReadJournal>(SqlReadJournal.Identifier); var sharedKillSwitch = KillSwitches.Shared("test"); var source = readJournal.EventsByTag(eventName, Offset.NoOffset()) .Via(sharedKillSwitch.Flow <EventEnvelope>()); var flow = FunctionTotalUsageFlow.Instance; var sink = FunctionTotalUsageSink.Create(Sys, eventName); source.Via(flow).To(sink).Run(Sys.Materializer()); await Task.Delay(5000); var projected = new FindProjectionQuery(dep.CreateFunctionUsageContext()).ExecuteForFunctionsTotalUsage(); Assert.Equal(3, projected.Sequence); var usage = await new FunctionsTotalUsageQuery(dep.CreateFunctionUsageContext()).Execute(); usage.Should().BeEquivalentTo( new FunctionTotalUsage { FunctionName = "AddChecked", InvocationsCount = 2 }, new FunctionTotalUsage { FunctionName = "SubtractChecked", InvocationsCount = 2 }, new FunctionTotalUsage { FunctionName = "MultiplyChecked", InvocationsCount = 1 }, new FunctionTotalUsage { FunctionName = "Divide", InvocationsCount = 1 }); }
public void A_SharedKillSwitch_must_provide_flows_that_materialize_to_its_owner_KillSwitch() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var t = Source.Maybe <int>() .ViaMaterialized(killSwitch.Flow <int>(), Keep.Right) .ToMaterialized(Sink.Ignore <int>(), Keep.Both) .Run(Materializer); var killSwitch2 = t.Item1; var completion = t.Item2; killSwitch2.Should().Be(killSwitch); killSwitch2.Shutdown(); completion.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue(); completion.IsFaulted.Should().BeFalse(); }, Materializer); }
public void A_SharedKillSwitch_must_complete_immediately_flows_materialized_after_switch_shutdown() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); killSwitch.Shutdown(); var t = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1; var downstream = t.Item2; upstream.ExpectCancellation(); downstream.ExpectSubscriptionAndComplete(); }, Materializer); }
public void Unique_kill_switch_must_control_graph_completion_with_shutdown() { #region unique-shutdown var countingSrc = Source.From(Enumerable.Range(1, int.MaxValue)).Delay(1.Seconds(), DelayOverflowStrategy.Backpressure); var lastSink = Sink.Last <int>(); var(killSwitch, last) = countingSrc .ViaMaterialized(KillSwitches.Single <int>(), Keep.Right) .ToMaterialized(lastSink, Keep.Both) .Run(Materializer); DoSomethingElse(); killSwitch.Shutdown(); AwaitCondition(() => last.IsCompleted); #endregion }
public void Unique_kill_switch_must_control_graph_completion_with_abort() { #region unique-abort var countingSrc = Source.From(Enumerable.Range(1, int.MaxValue)).Delay(1.Seconds(), DelayOverflowStrategy.Backpressure); var lastSink = Sink.Last <int>(); var(killSwitch, last) = countingSrc .ViaMaterialized(KillSwitches.Single <int>(), Keep.Right) .ToMaterialized(lastSink, Keep.Both) .Run(Materializer); var error = new Exception("boom"); killSwitch.Abort(error); last.Wait(1.Seconds()); last.Exception.Should().Be(error); #endregion }
public void A_SharedKillSwitch_must_not_affect_streams_corresponding_to_another_KillSwitch() { this.AssertAllStagesStopped(() => { var killSwitch1 = KillSwitches.Shared("switch"); var killSwitch2 = KillSwitches.Shared("switch"); var t1 = this.SourceProbe <int>() .Via(killSwitch1.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var t2 = this.SourceProbe <int>() .Via(killSwitch2.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream1 = t1.Item1; var downstream1 = t1.Item2; var upstream2 = t2.Item1; var downstream2 = t2.Item2; downstream1.Request(1); upstream1.SendNext(1); downstream1.ExpectNext(1); downstream2.Request(1); upstream2.SendNext(2); downstream2.ExpectNext(2); killSwitch1.Shutdown(); upstream1.ExpectCancellation(); downstream1.ExpectComplete(); upstream2.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); downstream2.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); var testException = new TestException("Abort"); killSwitch2.Abort(testException); upstream1.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); downstream1.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); upstream2.ExpectCancellation(); downstream2.ExpectError().InnerException.Should().Be(testException); }, Materializer); }
public void A_UniqueKillSwitch_must_stop_a_stream_if_requested() { var t = this.SourceProbe <int>() .ViaMaterialized(KillSwitches.Single <int>(), Keep.Both) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1.Item1; var killSwitch = t.Item1.Item2; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); killSwitch.Shutdown(); upstream.ExpectCancellation(); downstream.ExpectComplete(); }
public void A_SharedKillSwitch_must_fail_immediately_flows_materialized_after_switch_failure() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var testException = new TestException("Abort"); killSwitch.Abort(testException); var t = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1; var downstream = t.Item2; upstream.ExpectCancellation(); downstream.ExpectSubscriptionAndError().InnerException.Should().Be(testException); }, Materializer); }
public void Shared_kill_switch_must_control_graph_completion_with_abort() { #region shared-abort var countingSrc = Source.From(Enumerable.Range(1, int.MaxValue)).Delay(1.Seconds()); var lastSink = Sink.Last <int>(); var sharedKillSwitch = KillSwitches.Shared("my-kill-switch"); var last1 = countingSrc.Via(sharedKillSwitch.Flow <int>()).RunWith(lastSink, Materializer); var last2 = countingSrc.Via(sharedKillSwitch.Flow <int>()).RunWith(lastSink, Materializer); var error = new Exception("boom"); sharedKillSwitch.Abort(error); last1.Wait(1.Seconds()); last1.Exception.Should().Be(error); last2.Wait(1.Seconds()); last2.Exception.Should().Be(error); #endregion }
public void A_UniqueKillSwitch_must_ignore_completion_after_already_completed() { var t = this.SourceProbe <int>() .ViaMaterialized(KillSwitches.Single <int>(), Keep.Both) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1.Item1; var killSwitch = t.Item1.Item2; var downstream = t.Item2; upstream.EnsureSubscription(); downstream.EnsureSubscription(); killSwitch.Shutdown(); upstream.ExpectCancellation(); downstream.ExpectComplete(); killSwitch.Abort(new TestException("Won't happen")); upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); downstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); }
public void Hubs_must_demonstrate_combination() { void WriteLine(string s) => TestActor.Tell(s); #region pub-sub-1 // Obtain a Sink and Source which will publish and receive from the "bus" respectively. var(sink, source) = MergeHub .Source <string>(perProducerBufferSize: 16) .ToMaterialized(BroadcastHub.Sink <string>(bufferSize: 256), Keep.Both) .Run(Materializer); #endregion #region pub-sub-2 // Ensure that the Broadcast output is dropped if there are no listening parties. // If this dropping Sink is not attached, then the broadcast hub will not drop any // elements itself when there are no subscribers, backpressuring the producer instead. source.RunWith(Sink.Ignore <string>(), Materializer); #endregion #region pub-sub-3 // We create now a Flow that represents a publish-subscribe channel using the above // started stream as its "topic". We add two more features, external cancellation of // the registration and automatic cleanup for very slow subscribers. Flow <string, string, UniqueKillSwitch> busFlow = Flow.FromSinkAndSource(sink, source) .JoinMaterialized(KillSwitches.SingleBidi <string, string>(), Keep.Right) .BackpressureTimeout(TimeSpan.FromSeconds(3)); #endregion #region pub-sub-4 UniqueKillSwitch killSwitch = Source .Repeat("Hello world!") .ViaMaterialized(busFlow, Keep.Right) .To(Sink.ForEach <string>(WriteLine)) .Run(Materializer); // Shut down externally killSwitch.Shutdown(); #endregion }
public void A_SharedKillSwitch_must_stop_a_stream_if_requested() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var t = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); killSwitch.Shutdown(); upstream.ExpectCancellation(); downstream.ExpectComplete(); }, Materializer); }
public void A_UniqueKillSwitch_must_fail_a_stream_if_requested() { var t = this.SourceProbe <int>() .ViaMaterialized(KillSwitches.Single <int>(), Keep.Both) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1.Item1; var killSwitch = t.Item1.Item2; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); var testException = new TestException("Abort"); killSwitch.Abort(testException); upstream.ExpectCancellation(); //is a AggregateException from the Task downstream.ExpectError().InnerException.Should().Be(testException); }
public void A_SharedKillSwitch_must_fail_a_stream_if_requested() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var t = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var upstream = t.Item1; var downstream = t.Item2; downstream.Request(1); upstream.SendNext(1); downstream.ExpectNext(1); var testException = new TestException("Abort"); killSwitch.Abort(testException); upstream.ExpectCancellation(); downstream.ExpectError().InnerException.Should().Be(testException); }, Materializer); }
public void A_SharedKillSwitch_must_provide_a_flow_that_if_materialized_multiple_times_with_multiple_types_fails_all_streams_if_requested() { this.AssertAllStagesStopped(() => { var killSwitch = KillSwitches.Shared("switch"); var t1 = this.SourceProbe <int>() .Via(killSwitch.Flow <int>()) .ToMaterialized(this.SinkProbe <int>(), Keep.Both) .Run(Materializer); var t2 = this.SourceProbe <string>() .Via(killSwitch.Flow <string>()) .ToMaterialized(this.SinkProbe <string>(), Keep.Both) .Run(Materializer); var upstream1 = t1.Item1; var downstream1 = t1.Item2; var upstream2 = t2.Item1; var downstream2 = t2.Item2; downstream1.Request(1); upstream1.SendNext(1); downstream1.ExpectNext(1); downstream2.Request(2); upstream2.SendNext("A").SendNext("B"); downstream2.ExpectNext("A", "B"); var testException = new TestException("Abort"); killSwitch.Abort(testException); upstream1.ExpectCancellation(); upstream2.ExpectCancellation(); downstream1.ExpectError().InnerException.Should().Be(testException); downstream2.ExpectError().InnerException.Should().Be(testException); }, Materializer); }
static Task <int> Stream() { // 1秒ごとに下流に各要素を放出する Source Source <int, NotUsed> source = Source.From(Enumerable.Range(1, 100)); // 上流から流れてきた要素を足し合わせる Sink Sink <int, Task <int> > sink = Sink.Aggregate <int, int>(0, (l, r) => l + r); // Stream を正常(もしくはキャンセル扱いで)に停止させるための KillSwitch Flow <int, int, UniqueKillSwitch> killSwitch = Flow.Create <int>().ViaMaterialized(KillSwitches.Single <int>(), Keep.Right); // Stream(の特定の部分)を通過する要素の流量を制御するための Throttle Flow <int, int, NotUsed> throttle = Flow.Create <int>().Throttle(1, TimeSpan.FromSeconds(1), 1, ThrottleMode.Shaping); // Stream を動作させる Actor をホストする ActorSystem ActorSystem system = ActorSystem.Create("akkanet"); // ActorSystem を使用して Stream をマテリアル化するマテリアライザ ActorMaterializer materializer = ActorMaterializer.Create(system); // Source、Sink、Throttle、KillSwitch を使用して RunnableGraph(実行可能なグラフ)を組み立てる IRunnableGraph <Tuple <UniqueKillSwitch, Task <int> > > runnable = source .Via(throttle) .ViaMaterialized(killSwitch, Keep.Right) .ToMaterialized(sink, Keep.Both); // RunnableGraph をマテリアライズして Stream を作動させる var(ks, mat) = runnable.Run(materializer); // 10秒後に KillSwitch を使用して Stream を途中で停止させる(完了扱い) ICancelable canceller = materializer.ScheduleOnce(TimeSpan.FromSeconds(10), () => { Console.WriteLine("Stream is cancelled"); ks.Shutdown(); }); // Stream 完了後に ActorSystem と ActorMaterializer を破棄する return(mat.ContinueWith(prev => { canceller.Cancel(); materializer.Dispose(); system.Dispose(); return prev.Result; })); }