public static Source <CommittableIncomingMessage, Akka.NotUsed> CommittableQueueWithWithBackoff(Action <SimpleQueueOptions> opt) { return(RestartSource.WithBackoff(() => CommittableQueue(opt), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(30), 0.2)); }
public void A_restart_with_backoff_source_should_restart_on_failure() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); var enumerable = new List <string> { "a", "b", "c" }.Select(c => { if (c == "c") { throw new ArgumentException("failed"); } return(c); }); return(Source.From(enumerable)); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("b"); probe.RequestNext("a"); probe.RequestNext("b"); probe.RequestNext("a"); created.Current.Should().Be(3); probe.Cancel(); }, Materializer); }
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_restart_with_backoff_source_should_allow_using_withMaxRestarts_instead_of_minBackoff_to_determine_the_maxRestarts_reset_time() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" }).TakeWhile(c => c != "b")); }, _shortRestartSettings.WithMaxRestarts(2, TimeSpan.FromSeconds(1))) .RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("a"); Thread.Sleep(_shortMinBackoff + TimeSpan.FromTicks(_shortMinBackoff.Ticks * 2) + _shortMinBackoff); // if using shortMinBackoff as deadline cause reset probe.RequestNext("a"); probe.Request(1); probe.ExpectComplete(); created.Current.Should().Be(3); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_cancel_the_currently_running_source_when_cancelled() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var tcs = new TaskCompletionSource <Done>(); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" }) .WatchTermination((source, _) => { tcs.SetResult(Done.Instance); return source; })); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromSeconds(2), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.Cancel(); tcs.Task.Result.Should().BeSameAs(Done.Instance); // Wait to ensure it isn't restarted Thread.Sleep(200); created.Current.Should().Be(1); }, Materializer); }
public void A_restart_with_backoff_source_should_backoff_before_restart() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" })); }, TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(1000), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("b"); probe.Request(1); // There should be a delay of at least 200ms before we receive the element, wait for 100ms. var deadline = TimeSpan.FromMilliseconds(100).FromNow(); // But the delay shouldn't be more than 300ms. probe.ExpectNext(TimeSpan.FromMilliseconds(300), "a"); deadline.IsOverdue.Should().Be(true); created.Current.Should().Be(2); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_reset_maxRestarts_when_source_runs_for_at_least_minimum_backoff_without_completing() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.Single("a")); }, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), 0, maxRestarts: 2).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); // There should be minBackoff delay probe.RequestNext("a"); // The probe should now be backing off again with with increased backoff // Now wait for the delay to pass, then it will start the new source, we also want to wait for the // subsequent backoff to pass const int minBackoff = 1000; Thread.Sleep((minBackoff + (minBackoff * 2) + minBackoff + 500)); probe.RequestNext("a"); // We now are able to trigger the third restart, since enough time has elapsed to reset the counter probe.RequestNext("a"); created.Current.Should().Be(4); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_not_restart_the_source_when_maxRestarts_is_reached() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.Single("a")); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0, maxRestarts: 1).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("a"); probe.ExpectComplete(TimeSpan.FromSeconds(5)); created.Current.Should().Be(2); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_not_restart_the_source_when_cancelled_while_backing_off() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.Single("a")); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.Request(1); // Should be backing off now probe.Cancel(); // Wait to ensure it isn't restarted Thread.Sleep(300); created.Current.Should().Be(1); }, Materializer); }
public void A_restart_with_backoff_source_should_not_restart_the_source_when_maxRestarts_is_reached() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.Single("a")); }, _shortRestartSettings.WithMaxRestarts(1, _shortMinBackoff)) .RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("a"); probe.ExpectComplete(); created.Current.Should().Be(2); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_run_normally() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.Repeat("a")); }, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(20), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("a"); probe.RequestNext("a"); probe.RequestNext("a"); probe.RequestNext("a"); created.Current.Should().Be(1); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_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 probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" })); }, _restartSettings) .RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("b"); // There should be _minBackoff delay probe.RequestNext("a"); probe.RequestNext("b"); probe.Request(1); // The probe should now be backing off again with with increased backoff // Now wait for the delay to pass, then it will start the new source, we also want to wait for the // subsequent backoff to pass, so it resets the restart count Thread.Sleep(_minBackoff + TimeSpan.FromTicks(_minBackoff.Ticks * 2) + _minBackoff + TimeSpan.FromMilliseconds(500)); probe.ExpectNext("a"); probe.RequestNext("b"); // We should have reset, so the restart delay should be back, ie we should receive the // next element within < 2 * _minBackoff probe.RequestNext(TimeSpan.FromTicks(_minBackoff.Ticks * 2) - TimeSpan.FromMilliseconds(10)).Should().Be("a"); created.Current.Should().Be(4); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_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 probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" })); }, TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(2000), 0).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("b"); // There should be a 200ms delay probe.RequestNext("a"); probe.RequestNext("b"); probe.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.ExpectNext("a"); probe.RequestNext("b"); // We should have reset, so the restart delay should be back to 200ms, ie we should definitely receive the // next element within 300ms probe.RequestNext(TimeSpan.FromMilliseconds(300)).Should().Be("a"); created.Current.Should().Be(4); probe.Cancel(); }, Materializer); }
public void A_restart_with_backoff_source_should_restart_on_completion() { this.AssertAllStagesStopped(() => { var created = new AtomicCounter(0); var probe = RestartSource.WithBackoff(() => { created.IncrementAndGet(); return(Source.From(new List <string> { "a", "b" })); }, _shortRestartSettings).RunWith(this.SinkProbe <string>(), Materializer); probe.RequestNext("a"); probe.RequestNext("b"); probe.RequestNext("a"); probe.RequestNext("b"); probe.RequestNext("a"); created.Current.Should().Be(3); probe.Cancel(); }, Materializer); }
private static Source <TOut, NotUsed> RestartSourceFactory <TOut, TMat>(Func <Source <TOut, TMat> > flowFactory, TimeSpan minBackoff, TimeSpan maxBackoff, double randomFactor, int maxRestarts, bool onlyOnFailures) { return(onlyOnFailures ? RestartSource.OnFailuresWithBackoff(flowFactory, minBackoff, maxBackoff, randomFactor, maxRestarts) : RestartSource.WithBackoff(flowFactory, minBackoff, maxBackoff, randomFactor, maxRestarts)); }
protected override void OnStartup(StartupEventArgs e) { GUID = GetGUID(); _mtx = new Mutex(true, GUID, out var mtxSuccess); // 뮤텍스를 얻지 못하면 에러 if (!mtxSuccess) { MessageBox.Show("이미 실행중입니다."); Shutdown(); return; } try { var authority = AkkaHelper.ReadConfigurationFromHoconFile(Assembly.GetExecutingAssembly(), "conf") .WithFallback(ConfigurationFactory .FromResource <ConsumerSettings <object, object> >("Akka.Streams.Kafka.reference.conf")) .GetInt("ui.notification.authority-level"); if (authority < 1 || authority > 5) { MessageBox.Show("authority-level은 1~5까지 지정할 수 있습니다.", "Error"); Shutdown(); return; } var assembly = Assembly.GetExecutingAssembly(); var fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); _version = fileVersionInfo.ProductVersion; var config = AkkaHelper.ReadConfigurationFromHoconFile(Assembly.GetExecutingAssembly(), "conf") .WithFallback(ConfigurationFactory.FromResource <ConsumerSettings <object, object> >("Akka.Streams.Kafka.reference.conf")); CreateTrayIcon(config); CreateNotifier(config); var system = ActorSystem.Create("BLUECATS-ToastNotifier", config); notificationActor = system.ActorOf(NotificationActor.Props(Notifier), nameof(NotificationActor)); var parserActor = system.ActorOf(ParserActor.Props(notificationActor), nameof(ParserActor)); var eventSubscribeActor = system.ActorOf(EventSubscribeActor.Props(notificationActor), nameof(EventSubscribeActor)); system.EventStream.Subscribe(eventSubscribeActor, typeof(Akka.Event.Error)); var bootStrapServers = GetBootStrapServers(config); var consumerSettings = ConsumerSettings <Null, string> .Create(system, null, Deserializers.Utf8) .WithBootstrapServers(bootStrapServers) .WithGroupId(GUID); notificationActor.Tell((NotificationLevel.Info, $"BLUE CATS: Client Start\n{GUID}")); RestartSource.WithBackoff(() => KafkaConsumer.PlainSource(consumerSettings, GetSubscription(config)), minBackoff: TimeSpan.FromSeconds(3), maxBackoff: TimeSpan.FromSeconds(30), randomFactor: 0.2) .RunForeach(result => { parserActor.Tell(result); }, system.Materializer()); } catch (Exception ex) { MessageBox.Show(ex.ToString()); Current.Shutdown(); } base.OnStartup(e); }