public void SendAsync_BackOffExceptionHandler_Throw_Max2Minutes() { // create exponential back-off without delta interval, so expected seconds are exactly 1, 2, 4, 8, etc. var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); SubtestSendAsync_BackOffExceptionHandler(true, initializer); }
private void InitializeExponentialBackOff(ConfigurableHttpClient client, IFcmClientSettings settings) { // The Maximum Number of Retries is limited to 3 per default for a ConfigurableHttpClient. This is // somewhat weird, because the ExponentialBackOff Algorithm is initialized with 10 Retries per default. // // Somehow the NumTries seems to be the limiting factor here, so it basically overrides anything you // are going to write in the Exponential Backoff Handler. client.MessageHandler.NumTries = settings.ExponentialBackOffSettings.MaxNumberOfRetries; // Create the Default BackOff Algorithm: var backoff = new ExponentialBackOff(settings.ExponentialBackOffSettings.DeltaBackOff, settings.ExponentialBackOffSettings.MaxNumberOfRetries); // Create the Initializer. Make sure to set the Maximum Timespan between two Requests. It // is 16 Seconds per Default: var backoffInitializer = new BackOffHandler.Initializer(backoff) { MaxTimeSpan = settings.ExponentialBackOffSettings.MaxTimeSpan }; // Now create the Handler: var initializer = new ExponentialBackOffInitializer(ExponentialBackOffPolicy.UnsuccessfulResponse503, () => new BackOffHandler(backoffInitializer)); // And finally append the BackOff Handler, which reacts to 503 Requests: initializer.Initialize(client); }
public void SendAsync_BackOffUnsuccessfulResponseHandler_Cancel() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.ServiceUnavailable, initializer, 2); SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.ServiceUnavailable, initializer, 6); }
public void SendAsync_BackOffUnsuccessfulResponseHandler_ServiceUnavailable_Max10Hours() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)) { MaxTimeSpan = TimeSpan.FromHours(10) }; SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.ServiceUnavailable, initializer); }
public void SendAsync_BackOffExceptionHandler_Throw_Max1Hour() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)) { MaxTimeSpan = TimeSpan.FromHours(1) }; SubtestSendAsync_BackOffExceptionHandler(true, initializer); }
public void SendAsync_BackOffExceptionHandler_Throw_Max200Milliseconds() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)) { MaxTimeSpan = TimeSpan.FromMilliseconds(200) }; SubtestSendAsync_BackOffExceptionHandler(true, initializer); }
/// <summary>Subtest that back-off handler works as expected when exception is or isn't thrown.</summary> private void SubtestSendAsync_BackOffExceptionHandler(bool throwException, BackOffHandler.Initializer initializer, Exception exceptionToThrow = null) { var handler = new ExceptionMessageHandler { ThrowException = throwException }; if (exceptionToThrow != null) { handler.Exception = exceptionToThrow; } var configurableHanlder = new ConfigurableMessageHandler(handler); var boHandler = new MockBackOffHandler(initializer); configurableHanlder.AddExceptionHandler(boHandler); int boHandleCount = 0; // if an exception should be thrown and the handler can handle it then calculate the handle count by the // lg(MaxTimeSpan) if (throwException && initializer.HandleExceptionFunc(exceptionToThrow)) { boHandleCount = Math.Min((int)Math.Floor(Math.Log(boHandler.MaxTimeSpan.TotalSeconds, 2)) + 1, configurableHanlder.NumTries - 1); boHandleCount = boHandleCount >= 0 ? boHandleCount : 0; } using (var client = new HttpClient(configurableHanlder)) { var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler"); try { HttpResponseMessage response = client.SendAsync(request).Result; Assert.False(throwException); } catch (AggregateException ae) { Assert.True(throwException); // Don't compare exception messages because for TaskCanceledException the message // on Mono is different if there is a task associated with the exception. Assert.AreEqual(handler.Exception.GetType(), ae.InnerException.GetType()); } Assert.That(boHandler.Waits.Count, Is.EqualTo(boHandleCount)); // check the exponential behavior - wait 1, 2, 4, 8, ... seconds. if (throwException) { for (int i = 0; i < boHandler.Waits.Count; ++i) { Assert.That(boHandler.Waits[i].TotalSeconds, Is.EqualTo((int)Math.Pow(2, i))); } } Assert.That(handler.Calls, Is.EqualTo(boHandleCount + 1)); } }
public void SendAsync_BackOffExceptionHandler_DifferentHandler() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); initializer.HandleExceptionFunc = e => (e is InvalidCastException); SubtestSendAsync_BackOffExceptionHandler(true, initializer, new InvalidCastException()); initializer.HandleExceptionFunc = e => !(e is InvalidCastException); SubtestSendAsync_BackOffExceptionHandler(true, initializer, new InvalidCastException()); }
public void SendAsync_BackOffUnsuccessfulResponseHandler_Cancel() { // test back-off with maximum 30 minutes per single request var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)) { MaxTimeSpan = TimeSpan.FromMinutes(30) }; SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.ServiceUnavailable, initializer, 2); SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.ServiceUnavailable, initializer, 6); }
private static CreateHttpClientArgs CreateDefaultHttpClientArgs(IFcmClientSettings settings) { if (settings == null) { throw new ArgumentNullException("settings", "Settings are needed to create the Default HttpClientArgs"); } var args = new CreateHttpClientArgs(); // Create the Default BackOff Algorithm: var backoff = new ExponentialBackOff(settings.ExponentialBackOffSettings.DeltaBackOff, settings.ExponentialBackOffSettings.MaxNumberOfRetries); // Create the Initializer. Make sure to set the Maximum Timespan between two Requests. It is 16 Seconds per Default: var backoffInitializer = new BackOffHandler.Initializer(backoff) { MaxTimeSpan = settings.ExponentialBackOffSettings.MaxTimeSpan }; args.Initializers.Add(new ExponentialBackOffInitializer(ExponentialBackOffPolicy.UnsuccessfulResponse503, () => new BackOffHandler(backoffInitializer))); return(args); }
/// <summary> /// Subtest that back-off handler works as expected when a successful or abnormal response is returned. /// For testing the back-off handler in case of a canceled request, set the <code>cancelRequestNum</code> /// parameter to the index of the request you want to cancel. /// </summary> private void SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode statusCode, BackOffHandler.Initializer initializer, int cancelRequestNum = 0) { var handler = new UnsuccessfulResponseMessageHandler { ResponseStatusCode = statusCode }; CancellationToken cancellationToken = CancellationToken.None; bool cancel = cancelRequestNum > 0; if (cancel) { CancellationTokenSource tcs = new CancellationTokenSource(); handler.CancellationTokenSource = tcs; handler.CancelRequestNum = cancelRequestNum; cancellationToken = tcs.Token; } var configurableHanlder = new ConfigurableMessageHandler(handler); var boHandler = new MockBackOffHandler(initializer); configurableHanlder.UnsuccessfulResponseHandlers.Add(boHandler); int boHandleCount = 0; if (initializer.HandleUnsuccessfulResponseFunc != null && initializer.HandleUnsuccessfulResponseFunc(new HttpResponseMessage { StatusCode = statusCode })) { boHandleCount = Math.Min((int)Math.Floor(Math.Log(boHandler.MaxTimeSpan.TotalSeconds, 2)) + 1, configurableHanlder.NumTries - 1); boHandleCount = boHandleCount >= 0 ? boHandleCount : 0; if (cancel) { boHandleCount = Math.Min(boHandleCount, cancelRequestNum); } } using (var client = new HttpClient(configurableHanlder)) { var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler"); try { HttpResponseMessage response = client.SendAsync(request, cancellationToken).Result; Assert.False(cancel); } catch (AggregateException ae) { // a canceled request should throw an exception Assert.IsInstanceOf <TaskCanceledException>(ae.InnerException); Assert.True(cancel); } Assert.That(boHandler.Waits.Count, Is.EqualTo(boHandleCount)); // check the exponential behavior - wait 1, 2, 4, 8, ... seconds. for (int i = 0; i < boHandler.Waits.Count; ++i) { Assert.That(boHandler.Waits[i].TotalSeconds, Is.EqualTo((int)Math.Pow(2, i))); } // if the request was canceled the number of calls to the message handler is equal to the number of // calls to back-off handler Assert.That(handler.Calls, Is.EqualTo(boHandleCount + (cancel ? 0 : 1))); } }
public void SendAsync_BackOffUnsuccessfulResponseHandler_OK() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode.OK, initializer); }
public void SendAsync_BackOffExceptionHandler_DontThrow() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); SubtestSendAsync_BackOffExceptionHandler(false, initializer); }
public void SendAsync_BackOffExceptionHandler_ThrowCanceledException() { var initializer = new BackOffHandler.Initializer(new ExponentialBackOff(TimeSpan.Zero)); SubtestSendAsync_BackOffExceptionHandler(true, initializer, new TaskCanceledException()); }
/// <summary> Constructs a new back-off handler by the given initializer. </summary> public MockBackOffHandler(BackOffHandler.Initializer initializer) : base(initializer) { Waits = new List <TimeSpan>(); }