public async Task <ServiceResultModel> PostAsync(string uri, string key, StringContent content, ReturnType returnType) { var httpResponse = await _retryPolicyWrapper.ExecuteAsync(async() => { _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri); var response = await _client.PostAsync(uri, content); return(response); }); var result = new ServiceResultModel { HttpStatusCode = (int)httpResponse.StatusCode }; if (returnType == ReturnType.String) { result.Contents = await httpResponse.Content.ReadAsStringAsync(); result.Headers = httpResponse.Headers; } if (returnType == ReturnType.Binary) { result.Binary = await httpResponse.Content.ReadAsByteArrayAsync(); result.Headers = httpResponse.Headers; } return(result); }
public async Task ExecuteAsync_MultiplePolicies_WorkAsExpected() { // cache string url = "/api/cache"; string result = await _policyWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey1")); // typically cache key would be dynamic string result2 = await _policyWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey1")); Assert.IsTrue(!string.IsNullOrWhiteSpace(result)); Assert.AreEqual(result, result2); // inner timeout (500 ms), retry (5), outer timeout (this will exception as the inner timeouts will be retried enough times to trigger outer timeout) url = "/api/timeout/slow"; bool timeout = false; try { await _policyWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey2")); } catch (TimeoutRejectedException) { timeout = true; } Assert.IsTrue(timeout); // trying this again will trip circuit breaker before we get a chance to hit the outer timeout bool circuitIsBroken = false; try { string result3 = await _policyWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey3")); } catch (BrokenCircuitException) { circuitIsBroken = true; } Assert.IsTrue(circuitIsBroken); // lets try a fallback url = "/api/circuitbreaker/success"; var fallbackWrapper = FallbackPolicy <string> .Handle <Exception>() .FallbackAsync(context => Task.Run(() => "default")) .WrapAsync(_policyWrapper); string result4 = await fallbackWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey4")); Assert.AreEqual("default", result4); // let circuit breaker reset Task.Delay(3000).Wait(); string result5 = await fallbackWrapper.ExecuteAsync(async context => await _client.GetStringAsync(url), new Context("CacheKey5")); Assert.IsTrue(!string.IsNullOrWhiteSpace(result5)); Assert.AreNotEqual("default", result5); }
public async Task RetryAsync(Func <Task> func) { if (_asyncSinglePolicy != null) { await _asyncSinglePolicy.ExecuteAsync(func).ConfigureAwait(false); } else if (_asyncPolicyWrap != null) { await _asyncPolicyWrap.ExecuteAsync(func).ConfigureAwait(false); } await func().ConfigureAwait(false); }
public async Task Should_return_value_from_cache_and_not_execute_delegate_if_cache_holds_value_when_mid_policywrap() { const string valueToReturnFromCache = "valueToReturnFromCache"; const string valueToReturnFromExecution = "valueToReturnFromExecution"; const string executionKey = "SomeExecutionKey"; IAsyncCacheProvider stubCacheProvider = new StubCacheProvider(); CachePolicy cache = Policy.CacheAsync(stubCacheProvider, TimeSpan.MaxValue); Policy noop = Policy.NoOpAsync(); PolicyWrap wrap = Policy.WrapAsync(noop, cache, noop); await stubCacheProvider.PutAsync(executionKey, valueToReturnFromCache, new Ttl(TimeSpan.MaxValue), CancellationToken.None, false).ConfigureAwait(false); bool delegateExecuted = false; (await wrap.ExecuteAsync(async() => { delegateExecuted = true; await TaskHelper.EmptyTask.ConfigureAwait(false); return(valueToReturnFromExecution); }, new Context(executionKey)) .ConfigureAwait(false)) .Should().Be(valueToReturnFromCache); delegateExecuted.Should().BeFalse(); }
public async Task <ActionResult <HttpResponseMessage> > Get() { Func <Task <HttpResponseMessage> > myFun = async() => await CallFailesService(); Action <DelegateResult <HttpResponseMessage>, CircuitState, TimeSpan, Context> onBreak = (exception, state, timespan, context) => { }; Action <Context> onReset = context => { }; Action onHalfOpen = () => { }; retryPolicy = Policy .HandleResult <HttpResponseMessage> (r => r.StatusCode == System.Net.HttpStatusCode.InternalServerError) .WaitAndRetryAsync(4, i => PauseBetweenFailures); breaker = Policy.HandleResult <HttpResponseMessage> (r => r.StatusCode == System.Net.HttpStatusCode.InternalServerError) .CircuitBreakerAsync(2, PauseBetweenFailures, onBreak, onReset, onHalfOpen); myResilienceStrategy = Policy.WrapAsync(retryPolicy, breaker); var ret = await myResilienceStrategy.ExecuteAsync(async() => await myFun.Invoke()); return(ret); }
public async Task <string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer") { PolicyWrap <string> policyWrap = Policies.WaitAndRetryPolicy .WrapAsync(Policies.CircuitBreakerPolicy) .WrapAsync(Policies.FallbackForCircuitBreaker) .WrapAsync(Policies.FallbackForAnyException); var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); if (authorizationToken != null) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); } async Task <string> Action() { var response = await _client.SendAsync(requestMessage); return(await response.Content.ReadAsStringAsync()); } return(await policyWrap.ExecuteAsync(Action)); }
public async Task <string> GetAsync() { return(await _policyWrap.ExecuteAsync(() => { return QueryAsync(); })); }
private Task <T> HttpInvoker <T>(Func <Task <T> > action) { if (_singlePolicy == null) { return(_policyWrapper.ExecuteAsync(action)); } return(_singlePolicy.ExecuteAsync(action)); }
/// <summary> /// 重试并熔断 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="fun"></param> /// <returns></returns> public async Task <T> ExecRetryBreakerAsync <T>(Func <Task <T> > fun) { var cb = _policyRetryBreakerAsync.GetPolicy <CircuitBreakerPolicy>(); if (cb.CircuitState.HasFlag(CircuitState.Open)) { throw new Exception("处于熔断状态"); } return(await _policyRetryBreaker.ExecuteAsync(fun)); }
/// <inheritdoc /> public async Task <(Stream stream, string mediaType)> FetchAsync(Uri fetchUri) { var stopwatch = Stopwatch.StartNew(); var policyContext = new Context(fetchUri.ToString()); _logger.LogDebug("Start fetch request to {url}", fetchUri); using (var response = await _timeoutWithRetryPolicy.ExecuteAsync(FetchAction, policyContext, CancellationToken.None)) { stopwatch.Stop(); _fetchDurationMsMetric.Labels(fetchUri.Host).Observe(stopwatch.ElapsedMilliseconds); _logger.LogDebug("Fetch request executed in {elapsedMs} ms", stopwatch.ElapsedMilliseconds); if (!response.IsSuccessStatusCode) { _fetchErrorsMetric.Inc(); var content = await response.Content.ReadAsStringAsync(); _logger.LogError("Got status {status} on {method} request to {url} with content: {content}", response.StatusCode, HttpMethod.Get, fetchUri, content); throw new FetchRequestException(response.StatusCode, content); } if (response.Content.Headers.ContentLength > _maxBinarySize) { throw new FetchResponseTooLargeException(response.Content.Headers.ContentLength.Value); } if (string.IsNullOrEmpty(response.Content.Headers.ContentType.MediaType)) { throw new FetchResponseContentTypeInvalidException("Content type in response is not specified"); } var memoryStream = new MemoryStream(); using (var responseStream = await response.Content.ReadAsStreamAsync()) { int readBytes; var buffer = new byte[StreamCopyBufferSize]; do { readBytes = await responseStream.ReadAsync(buffer, 0, buffer.Length); await memoryStream.WriteAsync(buffer, 0, readBytes); if (memoryStream.Length > _maxBinarySize) { throw new FetchResponseTooLargeException(memoryStream.Length); } }while (readBytes > 0); } return(memoryStream, response.Content.Headers.ContentType.MediaType); } }
private async Task <HttpResponseMessage> ExecuteWithResiliencePolicies(Func <Task <HttpResponseMessage> > action) { var result = await _policy.ExecuteAsync(async() => { var response = await action(); if (response.ReportsServerError()) { // Throwing in the case of server-side errors allows // the circuit breaker to correclty open, if necessary throw new HttpRequestException($"{response.StatusCode} : {response.ReasonPhrase}"); } return(response); }); return(result); }
public async Task <string> GetSiteNamePolly(CancellationToken cancellationToken) { var myException = ""; try { return(await _policyWrap.ExecuteAsync(ct => ClientWrapper(), cancellationToken)); } catch (Exception e) { myException = e.Message; } return(myException); }
private async Task <InternalPersonDetails[]> MakeListPersonGroupRequest(string startPerson, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { string strResult = string.Empty; _log.Info($"Making ListPerson GET request requestId: {requestId} apiKey:{apiKey} start person {startPerson} ticks: {DateTime.Now.Ticks}"); InternalPersonDetails[] result = null; // Request parameters. string requestParameters = largegroupid + "/persons"; // Get the API URL and the API key from settings. var uriBase = ConfigurationManager.AppSettings["facePersonApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); // Assemble the URI for the REST API Call. var uri = uriBase + "/" + requestParameters; if (startPerson != string.Empty) { uri += "?start=" + startPerson; } try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.GetAsync(uri)); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <InternalPersonDetails[]>(); _log.Info($"ListPersonGroup completed: requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeListPersonGroupRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
public override async Task HandleExceptionAsync(Func <CancellationToken, Task> action, CancellationToken actionCancellationToken = default(CancellationToken), Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default(CancellationToken)) { try { await action(actionCancellationToken); } catch (Exception ex) { ExceptionHandlingUtility.WrapActionWithExceptionHandling(async() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); await policyWrap.ExecuteAsync(action, actionCancellationToken); } }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } }
public override async Task HandleExceptionAsync(Func <CancellationToken, Task> action, CancellationToken actionCancellationToken = default(CancellationToken), Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default(CancellationToken)) { try { await action(actionCancellationToken); } catch (Exception ex) { ExceptionHandlingUtility.WrapActionWithExceptionHandling(async() => { if (_splittedTransientFailureExceptions.IsNotNullOrEmpty() && _splittedTransientFailureExceptions.Contains(ex.GetType().Name) && _policies.IsNotNullOrEmpty()) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); await policyWrap.ExecuteAsync(action, actionCancellationToken); } }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } }
private async Task <FaceDetectResult[]> MakeFaceDetectRequest(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { _log.Info($"Making detect request requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); string strResult = string.Empty; FaceDetectResult[] result = null; // Request parameters. const string requestParameters = "returnFaceId=true&returnFaceLandmarks=false"; // Get the API URL and the API key from settings. var uriBase = ConfigurationManager.AppSettings["faceDetectApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Assemble the URI for the REST API Call. var uri = uriBase + "?" + requestParameters; try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetImageHttpContent(imageBytes))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"detect completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceDetectRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
public async Task <IActionResult> Get(int id) { var httpClient = GetHttpClient(); string requestEndpoint = $"inventory/{id}"; HttpResponseMessage response = await _policyWrap.ExecuteAsync( async token => await httpClient.GetAsync(requestEndpoint, token), CancellationToken.None); if (response.IsSuccessStatusCode) { int itemsInStock = JsonConvert.DeserializeObject <int>(await response.Content.ReadAsStringAsync()); return(Ok(itemsInStock)); } if (response.Content != null) { return(StatusCode((int)response.StatusCode, response.Content.ReadAsStringAsync())); } return(StatusCode((int)response.StatusCode)); }
public async Task <ActionResult <HttpResponseMessage> > Get() { Func <Task <HttpResponseMessage> > myFun = async() => await CallFailesService(); retryPolicy = Policy .HandleResult <HttpResponseMessage> (r => r.StatusCode == System.Net.HttpStatusCode.InternalServerError) .WaitAndRetryAsync(MaxRetryAttempts, i => PauseBetweenFailures); fallbackPolicy = Policy.HandleResult <HttpResponseMessage> (f => f.StatusCode == System.Net.HttpStatusCode.InternalServerError) .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK) { Content = new ObjectContent(typeof(string), "the system under maintentance", new JsonMediaTypeFormatter()) }); myResilienceStrategy = Policy.WrapAsync(fallbackPolicy, retryPolicy); var ret = await myResilienceStrategy.ExecuteAsync(async() => await myFun.Invoke()); return(ret); }
private async Task <FaceDetectResult[]> MakeFaceIdentifyRequest(FaceIdentifyRequest req, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { string strResult = string.Empty; StringBuilder faceids = new StringBuilder(); req.FaceIds.ToList().ForEach(s => faceids.Append(s + " ")); _log.Info($"Making identify request faceids: {faceids} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); FaceDetectResult[] result = null; // Get the API URL and the API key from settings. var uri = ConfigurationManager.AppSettings["faceIdentifyApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetIdentifyHttpContent(req))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"identify completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceIdentifyRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
public async Task <TOut> Execute <TOut>( Func <Task <TOut> > actionToExecute) { var retryPolicy = Policy <TOut> .Handle <HttpRequestException>().WaitAndRetryAsync(resilienceSettings.RetryCount, (i) => TimeSpan.FromMilliseconds(i * 1000), (result, retryDelay) => { logger.Error("The service call to failed with Error {@ex}", $"Retrying in...{retryDelay} s", result.Exception); }); var circuitBreakerPolicy = Policy <TOut> .Handle <HttpRequestException>().CircuitBreakerAsync(resilienceSettings.NumberOfErrorsBeforeBreakingCircuit, TimeSpan.FromSeconds(resilienceSettings.NumberOfSecondsToKeepCircuitBroken), (result, timespan) => { logger.Warning("Circuit Breaker opened! Result: {@result}", result); }, () => { logger.Warning("Circuit Breaker reset!"); }); PolicyWrap <TOut> policyWrapper = Policy.WrapAsync(new IAsyncPolicy <TOut>[] { retryPolicy, circuitBreakerPolicy }); var response = await policyWrapper.ExecuteAsync(actionToExecute); return(response); }
public override async Task <TReturn> HandleExceptionAsync <TReturn>(Func <CancellationToken, Task <TReturn> > func, CancellationToken funcCancellationToken = default(CancellationToken), Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default(CancellationToken)) { Task <TReturn> returnValue = default(Task <TReturn>); try { returnValue = await func(funcCancellationToken) as Task <TReturn>; } catch (Exception ex) { returnValue = await ExceptionHandlingUtility.WrapFuncWithExceptionHandling(async() => { if (_splittedTransientFailureExceptions.IsNotNullOrEmpty() && _splittedTransientFailureExceptions.Contains(ex.GetType().Name) && _policies.IsNotNullOrEmpty()) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); return(await policyWrap.ExecuteAsync(func, funcCancellationToken) as Task <TReturn>); } return(default(Task <TReturn>)); }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } return(await returnValue); }
public override async Task <TReturn> HandleExceptionAsync <TReturn>(Func <CancellationToken, Task <TReturn> > func, CancellationToken funcCancellationToken = default(CancellationToken), Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default(CancellationToken)) { Task <TReturn> returnValue = default(Task <TReturn>); try { returnValue = await func(funcCancellationToken) as Task <TReturn>; } catch (Exception ex) { returnValue = await ExceptionHandlingUtility.WrapFuncWithExceptionHandling(async() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); return(await policyWrap.ExecuteAsync(func, funcCancellationToken) as Task <TReturn>); } return(default(Task <TReturn>)); }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } return(await returnValue); }
public async Task ExecuteAsync(Func <Task> action) { await policies.ExecuteAsync(action); }
async Task <HttpResponseMessage> HttpInvoker(Func <Task <HttpResponseMessage> > operation) { return(await policyWrap.ExecuteAsync(operation)); }
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToTimeout = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(AsyncDemo09_Wrap_Fallback_Timeout_WaitAndRetry).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); Stopwatch watch = null; // Define our timeout policy: time out after 2 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it. var timeoutPolicy = Policy .TimeoutAsync(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic); // Define our waitAndRetry policy: keep retrying with 4 second gaps. This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry. var waitAndRetryPolicy = Policy .Handle <Exception>() // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define a fallback policy: provide a nice substitute message to the user, if we found the call was rejected due to the timeout policy. FallbackPolicy <String> fallbackForTimeout = Policy <String> .Handle <TimeoutRejectedException>() .FallbackAsync( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallbackAsync: async b => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToTimeout++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); /* do something else async if desired */ return("Please try again later [Fallback for any exception]"); }, onFallbackAsync: async e => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForTimeout).WrapAsync(timeoutPolicy).WrapAsync(waitAndRetryPolicy); using (var client = new HttpClient()) { totalRequests = 0; bool internalCancel = false; while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap string response = await policyWrap.ExecuteAsync(ct => client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); progress.Report(ProgressWithMessage("Response: " + response + "(after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public static async Task ExecuteAsync(CancellationToken cancellationToken) { Console.WriteLine(typeof(AsyncDemo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name); Console.WriteLine("======="); // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. var client = new HttpClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToCircuitBreaking = 0; int eventualFailuresForOtherReasons = 0; // Define our waitAndRetry policy: keep retrying with 200ms gaps. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { // This is your new exception handler! // Tell the user what they've won! ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { ConsoleHelper.WriteLineInColor(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ConsoleColor.Magenta); ConsoleHelper.WriteLineInColor("..due to: " + ex.Message, ConsoleColor.Magenta); }, onReset: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta), onHalfOpen: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta) ); // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap. PolicyWrap policyWrap = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable && !cancellationToken.IsCancellationRequested) { i++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string msg = await policyWrap.ExecuteAsync <String>(ct => { // This code is executed through both policies in the wrap: WaitAndRetry outer, then CircuitBreaker inner. Demo 06 shows a broken-out version of what this is equivalent to. return(client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + i)); }, cancellationToken); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteInColor("Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); ConsoleHelper.WriteInColor("Request " + i + " failed with: " + b.GetType().Name, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); ConsoleHelper.WriteInColor("Request " + i + " eventually failed with: " + e.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); } Console.WriteLine(""); Console.WriteLine("Total requests made : " + i); Console.WriteLine("Requests which eventually succeeded : " + eventualSuccesses); Console.WriteLine("Retries made to help achieve success : " + retries); Console.WriteLine("Requests failed early by broken circuit : " + eventualFailuresDueToCircuitBreaking); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }
private Task <T> HttpInvoker <T>(Func <Task <T> > action) => // Executes the action applying all // the policies defined in the wrapper _policyWrapper.ExecuteAsync(() => action());
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToCircuitBreaking = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(AsyncDemo08_Wrap_Fallback_WaitAndRetry_CircuitBreaker).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); Stopwatch watch = null; // Define our waitAndRetry policy: keep retrying with 200ms gaps. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { progress.Report(ProgressWithMessage(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta)); progress.Report(ProgressWithMessage("..due to: " + ex.Message, Color.Magenta)); }, onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Call ok! Closed the circuit again!", Color.Magenta)), onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: Next call is a trial!", Color.Magenta)) ); // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken. FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String> .Handle <BrokenCircuitException>() .FallbackAsync( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [message substituted by fallback policy]", onFallbackAsync: async b => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToCircuitBreaking++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); /* do something else async if desired */ return("Please try again later [Fallback for any exception]"); }, onFallbackAsync: async e => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // As demo07: we combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); // Added in demo08: we wrap the two fallback policies onto the front of the existing wrap too. Demonstrates the *instance* wrap syntax. And the fact that the PolicyWrap myResilienceStrategy from above is just another Policy, which can be onward-wrapped too. // With this pattern, you can build an overall resilience strategy programmatically, reusing some common parts (eg PolicyWrap myResilienceStrategy) but varying other parts (eg Fallback) individually for different calls. PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy)); // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.WrapAsync(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); totalRequests = 0; using (var client = new HttpClient()) { bool internalCancel = false; // Do the following until a key is pressed while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap string response = await policyWrap.ExecuteAsync(ct => client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); // Display the response message on the console progress.Report(ProgressWithMessage("Response : " + response + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public Task <MovieDetail> GetLatestMovieDetailListing(Movie movie) { return(_policyWrapMovieDetail.ExecuteAsync(() => GetMovieDetail(movie))); }
public Task <MovieList> GetLatestMovieListing() { return(_policyWrap.ExecuteAsync(() => GetMovies())); }