static void Main(string[] args) { int i = 0; while (i < 15) { var res = policy.Execute(() => { var rate = new Random().NextDouble(); Console.WriteLine($"rate = {rate}"); if (rate < 0.3) { throw new Exception("test"); } else if (rate >= 0.3 && rate < 0.6) { System.Threading.Thread.Sleep(1001); return("wong"); } else { return("catcher"); } }); Console.WriteLine(res); i++; } Console.WriteLine("Hello World!"); Console.Read(); }
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); } }
/// <summary> /// 重试并熔断 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="fun"></param> /// <returns></returns> public T ExecRetryBreaker <T>(Func <T> fun) { var cb = _policyRetryBreaker.GetPolicy <CircuitBreakerPolicy>(); if (cb.CircuitState.HasFlag(CircuitState.Open)) { throw new Exception("处于熔断状态"); } return(_policyRetryBreaker.Execute(fun)); }
static void Main(string[] args) { int i = 0; while (i < 15) { var res = policy.Execute(() => { throw new Exception("test"); }); i++; } Console.WriteLine("Hello World!"); Console.Read(); }
//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; }
public override void HandleException(Action action, Action onExceptionCompensatingHandler = null) { try { action(); } catch (Exception ex) { ExceptionHandlingUtility.WrapActionWithExceptionHandling(() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPolicies(ex, onExceptionCompensatingHandler); policyWrap.Execute(action); } }, _logger); HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler); } }
public override void HandleException(Action action, Action onExceptionCompensatingHandler = null) { try { action(); } catch (Exception ex) { ExceptionHandlingUtility.WrapActionWithExceptionHandling(() => { if (_splittedTransientFailureExceptions.IsNotNullOrEmpty() && _splittedTransientFailureExceptions.Contains(ex.GetType().Name) && _policies.IsNotNullOrEmpty()) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPolicies(ex, onExceptionCompensatingHandler); policyWrap.Execute(action); } }, _logger); HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler); } }
static void LoopCalls(PolicyWrap <UserPayload> policyWrap) { while (true) { try { Log.Information("Calling api to get values..."); policyWrap .Execute(() => { // substitute in IoC in real world scenario IJsonService service = new JsonService(new HttpClient()); //change the parameter here to 4 to trigger errors every time. var users = service.GetUsersWithExceptions(DateTime.Now.Second); if (users == null) { throw new HttpRequestException(); } foreach (User user in users) { Log.Information("User Name : {Name}", user.name); } return(new UserPayload { Users = users }); }); Thread.Sleep(2000); } catch (Exception ex) { Log.Error("Error occured in application : {Name}", ex.Message); Thread.Sleep(1000); } } }
public override TReturn HandleException <TReturn>(Func <TReturn> action, Action onExceptionCompensatingHandler = null) { TReturn returnValue = default(TReturn); try { returnValue = action(); } catch (Exception ex) { returnValue = ExceptionHandlingUtility.WrapFuncWithExceptionHandling(() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPolicies(ex, onExceptionCompensatingHandler); return(policyWrap.Execute(action)); } return(default(TReturn)); }, _logger); HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler); } return(returnValue); }
public override TReturn HandleException <TReturn>(Func <TReturn> action, Action onExceptionCompensatingHandler = null) { TReturn returnValue = default(TReturn); try { returnValue = action(); } catch (Exception ex) { returnValue = ExceptionHandlingUtility.WrapFuncWithExceptionHandling(() => { if (_splittedTransientFailureExceptions.IsNotNullOrEmpty() && _splittedTransientFailureExceptions.Contains(ex.GetType().Name) && _policies.IsNotNullOrEmpty()) { PolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPolicies(ex, onExceptionCompensatingHandler); return(policyWrap.Execute(action)); } return(default(TReturn)); }, _logger); HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler); } return(returnValue); }
public void 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"; ISyncCacheProvider stubCacheProvider = new StubCacheProvider(); CachePolicy <string> cache = Policy.Cache <string>(stubCacheProvider, TimeSpan.MaxValue); Policy <string> noop = Policy.NoOp <string>(); PolicyWrap <string> wrap = Policy.Wrap(noop, cache, noop); stubCacheProvider.Put(executionKey, valueToReturnFromCache, new Ttl(TimeSpan.MaxValue)); bool delegateExecuted = false; wrap.Execute(() => { delegateExecuted = true; return(valueToReturnFromExecution); }, new Context(executionKey)) .Should().Be(valueToReturnFromCache); delegateExecuted.Should().BeFalse(); }
public void Should_return_value_from_cache_and_not_execute_delegate_if_cache_holds_value_when_outermost_in_policywrap() { const string valueToReturnFromCache = "valueToReturnFromCache"; const string valueToReturnFromExecution = "valueToReturnFromExecution"; const string operationKey = "SomeOperationKey"; ISyncCacheProvider stubCacheProvider = new StubCacheProvider(); CachePolicy cache = Policy.Cache(stubCacheProvider, TimeSpan.MaxValue); Policy noop = Policy.NoOp(); PolicyWrap wrap = Policy.Wrap(cache, noop); stubCacheProvider.Put(operationKey, valueToReturnFromCache, new Ttl(TimeSpan.MaxValue)); bool delegateExecuted = false; wrap.Execute(ctx => { delegateExecuted = true; return(valueToReturnFromExecution); }, new Context(operationKey)) .Should().Be(valueToReturnFromCache); delegateExecuted.Should().BeFalse(); }
/// <summary> /// Remove the specified cacheKey. /// </summary> /// <param name="cacheKey">Cache key.</param> public void Remove(string cacheKey) { ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey)); try { // distributed cache at first _distributedCache.Remove(cacheKey); } catch (Exception ex) { LogMessage($"remove cache key [{cacheKey}] error", ex); } _localCache.Remove(cacheKey); // send message to bus _busSyncWrap.Execute(() => _bus.Publish(_options.TopicName, new EasyCachingMessage { Id = _cacheId, CacheKeys = new string[] { cacheKey } })); }
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 wait and retry policy 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! .WaitAndRetryForever( sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(200), // wait 200ms between each try onRetry: (exception, calculatedWaitDuration) => { // this is the new exception handler ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // define circuit breaker policy. Break if the action fails 4 times in a row var circuitBreakerPolicy = Policy.Handle <Exception>().CircuitBreaker( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + " ms!", ConsoleColor.Magenta); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss") + "]" + "..due to: " + ex.Message, ConsoleColor.Magenta); }, onReset: () => ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta), onHalfOpen: () => ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta) ); 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>(() => { return(client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); }); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + " (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); ConsoleHelper.WriteInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "Request " + i + " failed with: " + b.GetType().Name, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "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 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, // 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; } } }
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 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); // 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; } } }
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(Demo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); // 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! 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)) ); // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap. PolicyWrap policyWrap = Policy.Wrap(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++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string response = policyWrap.Execute <String>( ct => // The Execute() overload takes a CancellationToken, but it happens the executed code does not honour it. { // 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/" + totalRequests)); } , cancellationToken // The cancellationToken passed in to Execute() enables the policy instance to cancel retries, when the token is signalled. ); // 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 progress.Report(ProgressWithMessage("Response : " + response + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); progress.Report(ProgressWithMessage("Request " + totalRequests + " failed with: " + b.GetType().Name + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); progress.Report(ProgressWithMessage("Request " + totalRequests + " eventually failed with: " + e.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } // Wait half second Thread.Sleep(500); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public void Execute(Action operation) { _retryPolicy.Execute(operation); }
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; } } }