public CatalogController() { _timeoutPolicy = Policy.TimeoutAsync(1, onTimeoutAsync: TimeoutDelegate); _httpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode) .Or <TimeoutRejectedException>() .RetryAsync(3, onRetry: HttpRetryPolicyDelegate); _httpRequestFallbackPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode) .Or <TimeoutRejectedException>() .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK) { Content = new ObjectContent(_cachedResult.GetType(), _cachedResult, new JsonMediaTypeFormatter()) }, onFallbackAsync: HttpRequestFallbackPolicyDelegate); _policyWrap = _httpRequestFallbackPolicy.WrapAsync(_httpRetryPolicy.WrapAsync(_timeoutPolicy)); }
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 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 PollyServiceClient() { _client = new HttpClient(); _gatewayUri = _primaryUri; var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { //Called when circuit first open //Setting the backupUri so calls now go to backup gateway _gatewayUri = _backupUri; }, onReset: () => { //Called when circuit is closed again. //Primary gateway is responding again, setting to primaryUri. _gatewayUri = _primaryUri; }, onHalfOpen: () => { //Called when the policy is going to check the original call to see if there are no exceptions. //Send the call to the primary gateway to see if it's operational again. _gatewayUri = _primaryUri;; } ); 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) => { //Handle the exception here. }); FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String> .Handle <BrokenCircuitException>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); //This is called after the circuit breaker is tripped //and the gatewayUri is changed to point to the backup //gateway. This call runs on the backup gateway. return(await ClientWrapper()); }, onFallbackAsync: async e => { await Task.FromResult(true); } ); //Something really bad has happened. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); return("Another exception occurred."); }, onFallbackAsync: async e => { await Task.FromResult(true); } ); PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); _policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy)); }