public static void OutputState() { ConsoleHelper.WriteInColor(String.Format(" Good endpoint: requested {0:00}, ", goodRequestsMade), ConsoleColor.White); ConsoleHelper.WriteInColor(String.Format("succeeded {0:00}, ", goodRequestsSucceeded), ConsoleColor.Green); ConsoleHelper.WriteInColor(String.Format("pending {0:00}, ", goodRequestsMade - goodRequestsSucceeded - goodRequestsFailed), ConsoleColor.Yellow); ConsoleHelper.WriteLineInColor(String.Format("failed {0:00}.", goodRequestsFailed), ConsoleColor.Red); ConsoleHelper.WriteInColor(String.Format("Faulting endpoint: requested {0:00}, ", faultingRequestsMade), ConsoleColor.White); ConsoleHelper.WriteInColor(String.Format("succeeded {0:00}, ", faultingRequestsSucceeded), ConsoleColor.Green); ConsoleHelper.WriteInColor(String.Format("pending {0:00}, ", faultingRequestsMade - faultingRequestsSucceeded - faultingRequestsFailed), ConsoleColor.Yellow); ConsoleHelper.WriteLineInColor(String.Format("failed {0:00}.", faultingRequestsFailed), ConsoleColor.Red); Console.WriteLine(); }
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 static async Task ExecuteAsync(CancellationToken cancellationToken) { Console.WriteLine(typeof(AsyncDemo06_WaitAndRetryNestingCircuitBreaker).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) ); 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 - 3 times. await waitAndRetryPolicy.ExecuteAsync(async token => { // This code is executed within the waitAndRetryPolicy string msg = await circuitBreakerPolicy.ExecuteAsync <String>(() => // Note how we can also Execute() a Func<TResult> and pass back the value. { // This code is executed within the circuitBreakerPolicy // Make a request and get a response return(client.GetStringAsync(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++; }, cancellationToken); } 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); }
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; // 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) => { // 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. 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) ); // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap. PolicyWrap policyWrap = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable) { i++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string msg = policyWrap.Execute <String>(() => { // 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.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); }); // Without the extra comments in the anonymous method { } above, it could even be as concise as this: // 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 (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 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 static async Task ExecuteAsync(CancellationToken cancellationToken) { Console.WriteLine(typeof(AsyncDemo09_Wrap_Fallback_Timeout_WaitAndRetry).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 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 .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) => { 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>() .FallbackAsync( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallbackAsync: async 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>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { /* do something else async if desired */ return("Please try again later [Fallback for any exception]"); }, onFallbackAsync: async 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.WrapAsync(fallbackForTimeout).WrapAsync(timeoutPolicy).WrapAsync(waitAndRetryPolicy).WrapAsync(waitAndRetryPolicy); int i = 0; while (!Console.KeyAvailable && !cancellationToken.IsCancellationRequested) { i++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap string msg = await policyWrap.ExecuteAsync(ct => 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 (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); } 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); }