// // Flow // /// <summary> /// Helps reuse all the SetupFlow code for both methods: WithBackoff, and OnlyOnFailuresWithBackoff /// </summary> private static Flow <TIn, TOut, NotUsed> RestartFlowFactory <TIn, TOut, TMat>(Func <Flow <TIn, TOut, TMat> > flowFactory, TimeSpan minBackoff, TimeSpan maxBackoff, double randomFactor, int maxRestarts, bool onlyOnFailures) { // choose the correct backoff method return(onlyOnFailures ? RestartFlow.OnFailuresWithBackoff(flowFactory, minBackoff, maxBackoff, randomFactor, maxRestarts) : RestartFlow.WithBackoff(flowFactory, minBackoff, maxBackoff, randomFactor, maxRestarts)); }
// // Flow // /// <summary> /// Helps reuse all the SetupFlow code for both methods: WithBackoff, and OnlyOnFailuresWithBackoff /// </summary> private static Flow <TIn, TOut, NotUsed> RestartFlowFactory <TIn, TOut, TMat>(Func <Flow <TIn, TOut, TMat> > flowFactory, bool onlyOnFailures, RestartSettings settings) { // choose the correct backoff method return(onlyOnFailures ? RestartFlow.OnFailuresWithBackoff(flowFactory, settings) : RestartFlow.WithBackoff(flowFactory, settings)); }
// // Flow // private Tuple <AtomicCounter, TestPublisher.Probe <string>, TestSubscriber.Probe <string>, TestPublisher.Probe <string>, TestSubscriber.Probe <string> > SetupFlow(TimeSpan minBackoff, TimeSpan maxBackoff) { var created = new AtomicCounter(0); var probe1 = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var flowInSource = probe1.Item1; var flowInProbe = probe1.Item2; var probe2 = this.SourceProbe <string>().ToMaterialized(BroadcastHub.Sink <string>(), Keep.Both).Run(Materializer); var flowOutProbe = probe2.Item1; var flowOutSource = probe2.Item2; // We can't just use ordinary probes here because we're expecting them to get started/restarted. Instead, we // simply use the probes as a message bus for feeding and capturing events. var probe3 = this.SourceProbe <string>().ViaMaterialized(RestartFlow.WithBackoff(() => { created.IncrementAndGet(); var snk = Flow.Create <string>() .TakeWhile(s => s != "cancel") .To(Sink.ForEach <string>(c => flowInSource.SendNext(c)) .MapMaterializedValue(task => task.ContinueWith( t1 => { if (t1.IsFaulted || t1.IsCanceled) { flowInSource.SendNext("in error"); } else { flowInSource.SendNext("in complete"); } }))); var src = flowOutSource.TakeWhile(s => s != "complete").Select(c => { if (c == "error") { throw new ArgumentException("failed"); } return(c); }).WatchTermination((s1, task) => { task.ContinueWith(_ => { flowInSource.SendNext("out complete"); return(NotUsed.Instance); }, TaskContinuationOptions.OnlyOnRanToCompletion); return(s1); }); return(Flow.FromSinkAndSource(snk, src)); }, minBackoff, maxBackoff, 0), Keep.Left) .ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var source = probe3.Item1; var sink = probe3.Item2; return(Tuple.Create(created, source, flowInProbe, flowOutProbe, sink)); }
public void A_restart_with_backoff_flow_should_run_normally() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var(source, sink) = this.SourceProbe <string>().ViaMaterialized(RestartFlow.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>()); }, _shortRestartSettings), Keep.Left).ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); source.SendNext("a"); sink.RequestNext("a"); source.SendNext("b"); sink.RequestNext("b"); created.Current.Should().Be(1); source.SendComplete(); }, Materializer); }
public void A_restart_with_backoff_flow_should_run_normally() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tuple = this.SourceProbe <string>().ViaMaterialized(RestartFlow.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>());; }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0), Keep.Left).ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var source = tuple.Item1; var sink = tuple.Item2; source.SendNext("a"); sink.RequestNext("a"); source.SendNext("b"); sink.RequestNext("b"); created.Current.Should().Be(1); source.SendComplete(); }, Materializer); }