Пример #1
0
        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();
        }
Пример #2
0
        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
        }
Пример #3
0
        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 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);
            }
Пример #5
0
        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));
        }
Пример #6
0
        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);
        }
Пример #7
0
        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
        }
Пример #8
0
        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
        }
Пример #9
0
        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();
        }
Пример #10
0
        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));
        }
Пример #11
0
        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);
        }
Пример #12
0
        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;
            }));
        }