public NameService() { timeoutPolicy = Policy.Timeout(2, TimeoutStrategy.Pessimistic); fallbackPolicy = Policy <string> .Handle <TimeoutRejectedException>() .Fallback(fallbackMessage); wrapPolicy = fallbackPolicy.Wrap(timeoutPolicy); breaker = Policy .Handle <Exception>() .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1), (exception, timeout) => { Console.WriteLine("================================= I broke ================================="); return; }, () => Console.WriteLine("I reset")); fallbackForCircuitBreaker = Policy <string> .Handle <BrokenCircuitException>() .FallbackAsync("Service unvailable at the moment [broken circuit]"); fallbackForAnyException = Policy <string> .Handle <Exception>() .FallbackAsync(fallbackMessage); breakerWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(breaker)); }
public override void Execute(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { Init(progress); var timeoutPolicy = Policy.Timeout(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic, (context, span, task) => { if (task.Status == TaskStatus.Running) { progress.Report(ProgressWithMessage($"Timeout policy called: call exceeded {span.TotalSeconds}s", Color.Magenta)); } }); RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetry( retryCount: 3, sleepDurationProvider: attempt => TimeSpan.FromSeconds(4), // Wait 4s between each try. onRetry: (exception, calculatedWaitDuration) => // Capture some info for logging! { // This is your new exception handler! // Tell the user what they've won! progress.Report(ProgressWithMessage("Retry is starting.... Logging: " + exception.Message, Color.Yellow)); }); FallbackPolicy <string> fallbackForAnyException = Policy <string> .Handle <Exception>() .Fallback( fallbackAction: () => "Please try again later [Fallback for any exception]", onFallback: e => { progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message, Color.Red)); } ); // Wrap the policies (timeout check on every request) var policyWrap = fallbackForAnyException.Wrap(waitAndRetryPolicy).Wrap(timeoutPolicy); using (var client = new WebClient()) { _totalRequests = 0; try { // Manage the call according to the whole policy wrap. progress.Report(ProgressWithMessage("Start polywrap")); string response = policyWrap.Execute(ct => client.DownloadString(Configuration.WEB_API_ROOT + "/api/speed/veryslow"), cancellationToken); progress.Report(ProgressWithMessage("Response: " + response, Color.Green)); progress.Report(ProgressWithMessage("===============================================")); _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); } } }
static void Wrap() { bool check = false; RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .Retry(6, onRetry: (exception, retryCount) => { Console.WriteLine($"====Retry===== : 呼叫 API 異常, 進行第 {retryCount} 次重試"); if (retryCount == 5) { check = true; } }); TimeoutPolicy timeoutPolicys = Policy .Timeout(TimeSpan.FromMilliseconds(1000), TimeoutStrategy.Pessimistic, onTimeout: (context, timespan, task) => { Console.WriteLine($"====TimeOut===== : execution timed out after {timespan} seconds."); }); FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: () => { Console.WriteLine("999999999"); return("123"); }, onFallback: e => { Console.WriteLine($"[Polly fallback] : 重試失敗, say goodbye"); } ); CircuitBreakerPolicy circuitPolicy = Policy .Handle <Exception>() .CircuitBreaker(3, TimeSpan.FromSeconds(0), (ex, ts) => { Console.WriteLine($"====CircuitBreaker [OnBreak]===== ts = {ts.Seconds}s ,ex.message = {ex.Message}"); }, () => { Console.WriteLine("AService OnReset"); }); try { PolicyWrap <String> policyWrap = fallbackForAnyException .Wrap(waitAndRetryPolicy) .Wrap(circuitPolicy) .Wrap(timeoutPolicys); policyWrap.Execute(() => doMockHTTPRequest(check)); } catch (Exception ex) { Console.WriteLine(ex); } }
//Wrap function body in Retry and Circuit breaker policies public HttpResponseMessage ExecuteWithRetryandCircuitBreaker(string uri, Func <HttpResponseMessage> func) { // PolicyWrap<HttpResponseMessage> resiliencePolicyWrap = Policy.Wrap(_retryPolicy, _circuitBreakerPolicy); // PolicyWrap<HttpResponseMessage> fallbackPolicyWrap = _fallbackForAnyExceptionPolicy.Wrap(resiliencePolicyWrap); // var res= fallbackPolicyWrap.Execute(() => func()); // var res = _fallbackPolicy.Execute(() =>_retryPolicy.Wrap(_circuitBreakerPolicy).Execute(() => func())); PolicyWrap <HttpResponseMessage> resiliencePolicyWrap = Policy.Wrap(_timeoutPolicy, _retryPolicy, _circuitBreakerPolicy); PolicyWrap <HttpResponseMessage> fallbackPolicyWrap = _fallbackPolicy.Wrap(_fallbackCircuitBreakerPolicy.Wrap(resiliencePolicyWrap)); var res = fallbackPolicyWrap.Execute(() => func()); return(res); //var res = _fallbackPolicy.Execute(() => _retryPolicy.Execute(() => func())); //return res; }
private static PolicyWrap <List <TestUser> > CreateWaitPolicy() { var fallBackValue = new List <TestUser>(); fallBackValue.Add(new TestUser { Username = "******", Password = "******", IsActive = true }); int retries = 0; // Define our timeout policy: time out after 50 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it. var timeoutPolicy = Policy .Timeout(TimeSpan.FromSeconds(50), 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. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { Console.WriteLine(".Log,then retry: " + exception.Message); 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 <List <TestUser> > fallbackForTimeout = Policy <List <TestUser> > .Handle <TimeoutRejectedException>() .Fallback( fallbackValue: fallBackValue, onFallback: b => { //Handle Exception information... Console.WriteLine(b.Exception.Message); return; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <List <TestUser> > policyWrap = fallbackForTimeout.Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy); return(policyWrap); }
private PolicyWrap <string> BuildPolicy() { // max timeout policy, to stop the entire request because of the API is being TOOO slow var timeoutPolicy = Policy.Timeout(TimeSpan.FromSeconds(TimeoutFallback), TimeoutStrategy.Pessimistic, (context, span, task) => { if (task.Status == TaskStatus.Running) { _progress.Report(ProgressWithMessage($"Timeout policy called: call exceeded {span.TotalSeconds}s", Color.Magenta)); } }); // fallback policy, what to do when a timeout is occured FallbackPolicy <string> fallbackForAnyException = Policy <string> .Handle <Exception>() .Fallback( fallbackAction: () => "Please try again later [Fallback for any exception]", onFallback: e => { _progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message, Color.Red)); } ); // wait and retry policy, when a call fails RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetry( retryCount: 3, sleepDurationProvider: attempt => TimeSpan.FromSeconds(4), // Wait 4s between each try. onRetry: (exception, calculatedWaitDuration) => // Capture some info for logging! { // This is your new exception handler! // Tell the user what they've won! _progress.Report(ProgressWithMessage("Retry is starting.... Logging: " + exception.Message, Color.Yellow)); }); // Wrap the policies together (timeout check on every request) return(fallbackForAnyException.Wrap(waitAndRetryPolicy).Wrap(timeoutPolicy)); }
public static void Execute() { Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.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 WebClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToCircuitBreaking = 0; int eventualFailuresForOtherReasons = 0; Stopwatch watch = null; // Define our waitAndRetry policy: keep retrying with 200ms gaps. RetryPolicy 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! .WaitAndRetryForever( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreaker( 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) ); // 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>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for broken circuit]", onFallback: b => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches eventually failed with: " + e.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } ); // As demo07: we combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.Wrap(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.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy)); // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.Wrap(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable) { i++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string msg = policyWrap.Execute(() => client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); 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 (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 Thread.Sleep(500); } 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); }
public override void Execute(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(Demo09_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 .Timeout(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. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( 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>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallback: b => { 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>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { 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.Wrap(fallbackForTimeout).Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy); using (var client = new WebClient()) { bool internalCancel = false; totalRequests = 0; while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string response = policyWrap.Execute(ct => client.DownloadString(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 Thread.Sleep(500); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
static void Main(string[] args) { Console.WriteLine("Hello World!"); Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day) .CreateLogger(); _circuitBreakerPolicy = Policy.Handle <HttpRequestException>() .CircuitBreaker( // number of exceptions before breaking circuit 5, // time circuit opened before retry TimeSpan.FromMinutes(1), (exception, duration) => { // on circuit opened Log.Information("Circuit breaker opened"); }, () => { // on circuit closed Log.Information("Circuit breaker reset"); }); _retryPolicy = Policy.Handle <HttpRequestException>() .WaitAndRetry( // number of retries 4, // exponential backofff retryAttempt => TimeSpan.FromSeconds(retryAttempt), // on retry (exception, timeSpan, retryCount, context) => { var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " + $"of {context.PolicyKey} " + $"at {context.ExecutionKey}"; Log.Warning(msg); }); // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken. FallbackPolicy <UserPayload> fallbackForCircuitBreaker = Policy <UserPayload> .Handle <BrokenCircuitException>() .Fallback( fallbackValue: new UserPayload { Users = null, ErrorMessage = "Please try again later [Fallback for broken circuit]" }, onFallback: b => { Log.Information("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <UserPayload> fallbackForAnyException = Policy <UserPayload> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return(new UserPayload { Users = null, ErrorMessage = "Please try again later [Fallback for any exception]" }); }, onFallback: e => { Log.Information("Fallback catches failed with: " + e.Exception.Message, ConsoleColor.DarkMagenta); } ); PolicyWrap myResilienceStrategy = Policy.Wrap(_retryPolicy, _circuitBreakerPolicy); PolicyWrap <UserPayload> policyWrap = fallbackForAnyException.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy)); LoopCalls(policyWrap); }
public static void Execute() { Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.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 WebClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToTimeout = 0; int eventualFailuresForOtherReasons = 0; 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 .Timeout(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. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.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>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallback: b => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToTimeout++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches eventually failed with: " + e.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <String> policyWrap = fallbackForAnyException.Wrap(fallbackForTimeout).Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy).Wrap(waitAndRetryPolicy); int i = 0; while (!Console.KeyAvailable) { i++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string msg = policyWrap.Execute(() => client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); 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 (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 Thread.Sleep(500); } 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 timed out by timeout policy : " + eventualFailuresDueToTimeout); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }
public override void Execute(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(Demo08_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. RetryPolicy 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! .WaitAndRetryForever( 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. CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreaker( 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>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [message substituted by fallback policy]", onFallback: b => { 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>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { 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.Wrap(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.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy)); // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.Wrap(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); using (var client = new WebClient()) { bool internalCancel = false; totalRequests = 0; // 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 = policyWrap.Execute(ct => client.DownloadString(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 Thread.Sleep(500); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public T Execute<T>(Func<T> operation, Func<T> openStateOperation) { // Define our waitAndRetry policy: keep retrying with n ms gaps. RetryPolicy 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! .WaitAndRetryForever( attempt => TimeSpan.FromMilliseconds(SiteSettings.Instance.SleepDurationsMilliseconds), (exception, calculatedWaitDuration) => { _log.Error(".Log, then retry: ", exception); }); // Define our CircuitBreaker policy: Break if the action fails n times in a row. CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle<Exception>() .CircuitBreaker( exceptionsAllowedBeforeBreaking: SiteSettings.Instance.ExceptionsAllowedBeforeBreaking, durationOfBreak: TimeSpan.FromSeconds(1), onBreak: (ex, breakDelay) => { _log.Error($".Breaker logging: Breaking the circuit for {breakDelay.TotalMilliseconds} + ms!"); _log.Error($"..due to: {ex.Message}"); }, onReset: () => { _log.Error(".Breaker logging: Call ok! Closed the circuit again!"); }, onHalfOpen: () => { _log.Error(".Breaker logging: Half-open: Next call is a trial!"); } ); // Define a fallback policy: provide a secondary services or substitute result to the user, for any exception. FallbackPolicy<T> fallbackForAnyException = Policy<T> .Handle<Exception>() .Fallback( fallbackAction: openStateOperation, onFallback: e => { _log.Error($"Fallback catches eventually failed with: {e.Exception.Message}"); } ); // We combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); // We wrap the two fallback policies onto the front of the existing wrap too. 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<T> policyWrap = fallbackForAnyException.Wrap(myResilienceStrategy); try { // Manage the call according to the whole policy wrap. var response = policyWrap.Execute(operation); return response; } 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. { _log.Error("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); return default(T); } }
public override void Execute(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(Demo09_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 .Timeout(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic, // This use of onTimeout demonstrates the point about capturing walked-away-from Tasks with TimeoutStrategy.Pessimistic discussed in the Polly wiki, here: https://github.com/App-vNext/Polly/wiki/Timeout#pessimistic-timeout-1 onTimeout: (ctx, span, abandonedTask) => { { abandonedTask.ContinueWith(t => { // ContinueWith important!: the abandoned task may very well still be executing, when the caller times out on waiting for it! if (t.IsFaulted) { progress.Report(ProgressWithMessage(".The task previously walked-away-from now terminated with exception: " + t.Exception.Message, Color.Yellow)); } else if (t.IsCanceled) { // (If the executed delegates do not honour cancellation, this IsCanceled branch may never be hit. It can be good practice however to include, in case a Policy configured with TimeoutStrategy.Pessimistic is used to execute a delegate honouring cancellation.) progress.Report(ProgressWithMessage(".The task previously walked-away-from now was canceled.", Color.Yellow)); } else { // extra logic (if desired) for tasks which complete, despite the caller having 'walked away' earlier due to timeout. progress.Report(ProgressWithMessage(".The task previously walked-away-from now eventually completed.", Color.Yellow)); } }); } } ); // 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. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( 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>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallback: b => { 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>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { 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.Wrap(fallbackForTimeout).Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy); using (var client = new WebClient()) { bool internalCancel = false; totalRequests = 0; while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string response = policyWrap.Execute(ct => client.DownloadString(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 Thread.Sleep(500); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }