Example #1
0
        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();
        }
Example #2
0
        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));
        }
Example #4
0
        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();
        }
Example #5
0
        //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;
        }
Example #6
0
 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);
     }
 }
Example #8
0
        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);
                }
            }
        }
Example #9
0
        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);
        }
Example #11
0
        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();
        }
Example #12
0
        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;
                }
            }
        }
Example #17
0
        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);
        }
Example #18
0
        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;
                }
            }
        }
Example #20
0
        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;
                }
            }
        }
Example #21
0
 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;
                }
            }
        }