public void A_restart_with_backoff_sink_should_not_restart_the_sink_when_completed_while_backing_off() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tuple = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var queue = tuple.Item1; var sinkProbe = tuple.Item2; var probe = this.SourceProbe <string>().ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true) .To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, TimeSpan.FromMilliseconds(200), TimeSpan.FromSeconds(2), 0), Keep.Left).Run(Materializer); probe.SendNext("a"); sinkProbe.RequestNext("a"); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // Should be backing off now probe.SendComplete(); // Wait to ensure it isn't restarted Thread.Sleep(300); created.Current.Should().Be(1); sinkProbe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_sink_should_backoff_before_restart() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tuple = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var queue = tuple.Item1; var sinkProbe = tuple.Item2; var probe = this.SourceProbe <string>().ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true) .To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, TimeSpan.FromMilliseconds(200), TimeSpan.FromSeconds(2), 0), Keep.Left).Run(Materializer); probe.SendNext("a"); sinkProbe.RequestNext("a"); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); probe.SendNext("b"); sinkProbe.Request(1); var deadline = TimeSpan.FromMilliseconds(100).FromNow(); sinkProbe.ExpectNext(TimeSpan.FromMilliseconds(300), "b"); deadline.IsOverdue.Should().BeTrue(); created.Current.Should().Be(2); sinkProbe.Cancel(); probe.SendComplete(); }, Materializer); }
public void A_restart_with_backoff_sink_should_run_normally() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tcs = new TaskCompletionSource <IEnumerable <string> >(); var probe = this.SourceProbe <string>().ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Sink.Seq <string>().MapMaterializedValue(task => { task.ContinueWith(c => tcs.SetResult(c.Result)); return Done.Instance; })); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0), Keep.Left).Run(Materializer); probe.SendNext("a"); probe.SendNext("b"); probe.SendNext("c"); probe.SendComplete(); tcs.Task.Result.Should().ContainInOrder("a", "b", "c"); created.Current.Should().Be(1); }, Materializer); }
public void A_restart_with_backoff_sink_should_not_restart_the_sink_when_maxRestarts_is_reached() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var(queue, sinkProbe) = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var probe = this.SourceProbe <string>() .ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true).To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, _shortRestartSettings.WithMaxRestarts(1, _shortMinBackoff)), Keep.Left) .Run(Materializer); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); probe.ExpectCancellation(); created.Current.Should().Be(2); sinkProbe.Cancel(); probe.SendComplete(); }, Materializer); }
public static Sink <ByteString, Akka.NotUsed> SimpleWithBackoff(Action <SimpleQueueOptions> opt) { return(RestartSink.WithBackoff(() => Simple(opt), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(30), 0.2)); }
public void A_restart_with_backoff_sink_should_reset_exponential_backoff_back_to_minimum_when_source_runs_for_at_least_minimum_backoff_without_completing() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tuple = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var queue = tuple.Item1; var sinkProbe = tuple.Item2; var probe = this.SourceProbe <string>().ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true) .To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, TimeSpan.FromMilliseconds(200), TimeSpan.FromSeconds(2), 0), Keep.Left).Run(Materializer); probe.SendNext("a"); sinkProbe.RequestNext("a"); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // There should be a 200ms delay probe.SendNext("b"); sinkProbe.RequestNext("b"); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); sinkProbe.Request(1); // The probe should now be backing off for 400ms // Now wait for the 400ms delay to pass, then it will start the new source, we also want to wait for the // subsequent 200ms min backoff to pass, so it resets the restart count Thread.Sleep(700); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // We should have reset, so the restart delay should be back to 200ms, ie we should definitely receive the // next element within 300ms probe.SendNext("c"); sinkProbe.Request(1); sinkProbe.ExpectNext(TimeSpan.FromMilliseconds(300), "c"); created.Current.Should().Be(4); sinkProbe.Cancel(); probe.SendComplete(); }, Materializer); }
public void A_restart_with_backoff_sink_should_reset_maxRestarts_when_sink_runs_for_at_least_minimum_backoff_without_completing() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var(queue, sinkProbe) = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var probe = this.SourceProbe <string>() .ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true).To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, _restartSettings.WithMaxRestarts(2, _minBackoff)), Keep.Left) .Run(Materializer); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // There should be a minBackoff delay probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // The probe should now be backing off for 2 * minBackoff // Now wait for the 2 * minBackoff delay to pass, then it will start the new source, we also want to wait for the // subsequent minBackoff to pass, so it resets the restart count Thread.Sleep(_minBackoff + TimeSpan.FromTicks(_minBackoff.Ticks * 2) + _minBackoff + TimeSpan.FromMilliseconds(500)); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // We now are able to trigger the third restart, since enough time has elapsed to reset the counter probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); created.Current.Should().Be(4); sinkProbe.Cancel(); probe.SendComplete(); }, Materializer); }
public void A_restart_with_backoff_sink_should_allow_using_withMaxRestarts_instead_of_minBackoff_to_determine_the_maxRestarts_reset_time() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var(queue, sinkProbe) = this.SourceProbe <string>().ToMaterialized(this.SinkProbe <string>(), Keep.Both).Run(Materializer); var probe = this.SourceProbe <string>() .ToMaterialized(RestartSink.WithBackoff(() => { created.IncrementAndGet(); return(Flow.Create <string>().TakeWhile(c => c != "cancel", inclusive: true).To(Sink.ForEach <string>(c => queue.SendNext(c)))); }, _shortRestartSettings.WithMaxRestarts(2, TimeSpan.FromSeconds(1))), Keep.Left) .Run(Materializer); probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // There should be a shortMinBackoff delay probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // The probe should now be backing off for 2 * shortMinBackoff Thread.Sleep(_shortMinBackoff + TimeSpan.FromTicks(_shortMinBackoff.Ticks * 2) + _shortMinBackoff); // if using shortMinBackoff as deadline cause reset probe.SendNext("cancel"); sinkProbe.RequestNext("cancel"); // We cannot get a final element probe.SendNext("cancel"); sinkProbe.Request(1); sinkProbe.ExpectNoMsg(); created.Current.Should().Be(3); sinkProbe.Cancel(); probe.SendComplete(); }, Materializer); }