public PollySqlConnection(string connectionString, IAsyncPolicy[] asyncPolicies, ISyncPolicy[] syncPolicies)
        {
            _connectionString = connectionString;
            _asyncPolicies    = asyncPolicies;
            _syncPolicies     = syncPolicies;

            if (asyncPolicies == null)
            {
                throw new ArgumentNullException($"{nameof(asyncPolicies)} must have at least one async policy provided");
            }

            if (asyncPolicies.Length == 1)
            {
                _singleAsyncPolicy = asyncPolicies[0];
            }
            else
            {
                _asyncPolicyWrapper = Policy.WrapAsync(asyncPolicies);
            }

            if (syncPolicies == null)
            {
                throw new ArgumentNullException($"{nameof(syncPolicies)} must have at least one sync policy provided");
            }

            if (syncPolicies.Length == 1)
            {
                _singleSyncPolicy = syncPolicies[0];
            }
            else
            {
                _syncPolicyWrapper = Policy.Wrap(syncPolicies);
            }

            _connection = new SqlConnection(connectionString);
        }
예제 #2
0
        private async Task <FaceDetectResult[]> MakeFaceIdentifyRequest(FaceIdentifyRequest req, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
        {
            string        strResult = string.Empty;
            StringBuilder faceids   = new StringBuilder();

            req.FaceIds.ToList().ForEach(s => faceids.Append(s + " "));
            _log.Info($"Making identify request faceids: {faceids} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}");
            FaceDetectResult[] result = null;
            // Get the API URL and the API key from settings.
            var uri = ConfigurationManager.AppSettings["faceIdentifyApiUrl"];

            // Configure the HttpClient request headers.
            _client.DefaultRequestHeaders.Clear();
            _client.DefaultRequestHeaders.Accept.Clear();
            _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
            //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            try
            {
                // Execute the REST API call, implementing our resiliency strategy.
                HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetIdentifyHttpContent(req)));

                // Get the JSON response.
                strResult = await response.Content.ReadAsStringAsync();

                result = await response.Content.ReadAsAsync <FaceDetectResult[]>();

                _log.Info($"identify completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}");
            }
            catch (BrokenCircuitException bce)
            {
                _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce);
            }
            catch (Exception e)
            {
                _log.Error($"Critical error-MakeFaceIdentifyRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e);
            }

            return(result);
        }
        /// <summary>
        /// Register instance in DI.
        /// </summary>
        /// <typeparam name="TClient">Interface implemented by a type.</typeparam>
        /// <typeparam name="TImplementation">A type implements TClient interface.</typeparam>
        /// <param name="services">instance of IServiceCollection.</param>
        /// <param name="policy">circuit breaker policy.</param>
        public static void RegisterInstace <TClient, TImplementation>(this IServiceCollection services, PolicyWrap <HttpResponseMessage> policy)
            where TClient : class
            where TImplementation : class, TClient
        {
            PolicyBuilder policyBuilder = new PolicyBuilder();

            services.AddHttpClient <TClient, TImplementation>()
            .AddPolicyHandler(t => { return(policy); })
            .CorrelateRequests("X-Correlation-ID")
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
            {
                AllowAutoRedirect      = false,
                AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
            });
        }
        public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress)
        {
            if (cancellationToken == null)
            {
                throw new ArgumentNullException(nameof(cancellationToken));
            }
            if (progress == null)
            {
                throw new ArgumentNullException(nameof(progress));
            }

            // Let's call a web api service to make repeated requests to a server.
            // The service is programmed to fail after 3 requests in 5 seconds.

            eventualSuccesses               = 0;
            retries                         = 0;
            eventualFailuresDueToTimeout    = 0;
            eventualFailuresForOtherReasons = 0;

            progress.Report(ProgressWithMessage(typeof(AsyncDemo09_Wrap_Fallback_Timeout_WaitAndRetry).Name));
            progress.Report(ProgressWithMessage("======"));
            progress.Report(ProgressWithMessage(String.Empty));

            Stopwatch watch = null;

            // Define our timeout policy: time out after 2 seconds.  We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it.
            var timeoutPolicy = Policy
                                .TimeoutAsync(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic);

            // Define our waitAndRetry policy: keep retrying with 4 second gaps.  This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry.
            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>() // Exception filtering!  We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromSeconds(4),
                (exception, calculatedWaitDuration) =>
            {
                progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow));
                retries++;
            });

            // Define a fallback policy: provide a nice substitute message to the user, if we found the call was rejected due to the timeout policy.
            FallbackPolicy <String> fallbackForTimeout = Policy <String>
                                                         .Handle <TimeoutRejectedException>()
                                                         .FallbackAsync(
                fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]",
                onFallbackAsync: async b =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresDueToTimeout++;
            }
                );

            // Define a fallback policy: provide a substitute string to the user, for any exception.
            FallbackPolicy <String> fallbackForAnyException = Policy <String>
                                                              .Handle <Exception>()
                                                              .FallbackAsync(
                fallbackAction: /* Demonstrates fallback action/func syntax */ async ct =>
            {
                await Task.FromResult(true);
                /* do something else async if desired */
                return("Please try again later [Fallback for any exception]");
            },
                onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresForOtherReasons++;
            }
                );

            // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go.
            PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForTimeout).WrapAsync(timeoutPolicy).WrapAsync(waitAndRetryPolicy);

            using (var client = new HttpClient())
            {
                totalRequests = 0;
                bool internalCancel = false;

                while (!internalCancel && !cancellationToken.IsCancellationRequested)
                {
                    totalRequests++;
                    watch = new Stopwatch();
                    watch.Start();

                    try
                    {
                        // Manage the call according to the whole policy wrap
                        string response = await policyWrap.ExecuteAsync(ct =>
                                                                        client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken);

                        watch.Stop();

                        progress.Report(ProgressWithMessage("Response: " + response + "(after " + watch.ElapsedMilliseconds + "ms)", Color.Green));

                        eventualSuccesses++;
                    }
                    catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>.  It's only been left in to *demonstrate* it should never get hit.
                    {
                        throw new InvalidOperationException("Should never arrive here.  Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e);
                    }

                    // Wait half second
                    await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);

                    internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable;
                }
            }
        }
        public static async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine(typeof(AsyncDemo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name);
            Console.WriteLine("=======");
            // Let's call a web api service to make repeated requests to a server.
            // The service is programmed to fail after 3 requests in 5 seconds.

            var client            = new HttpClient();
            int eventualSuccesses = 0;
            int retries           = 0;
            int eventualFailuresDueToCircuitBreaking = 0;
            int eventualFailuresForOtherReasons      = 0;

            // Define our waitAndRetry policy: keep retrying with 200ms gaps.
            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering!  We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromMilliseconds(200),
                (exception, calculatedWaitDuration) =>
            {
                // This is your new exception handler!
                // Tell the user what they've won!
                ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow);
                retries++;
            });

            // Define our CircuitBreaker policy: Break if the action fails 4 times in a row.
            var circuitBreakerPolicy = Policy
                                       .Handle <Exception>()
                                       .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 4,
                durationOfBreak: TimeSpan.FromSeconds(3),
                onBreak: (ex, breakDelay) =>
            {
                ConsoleHelper.WriteLineInColor(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ConsoleColor.Magenta);
                ConsoleHelper.WriteLineInColor("..due to: " + ex.Message, ConsoleColor.Magenta);
            },
                onReset: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta),
                onHalfOpen: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta)
                );

            // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap.
            PolicyWrap policyWrap = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy);

            int i = 0;

            // Do the following until a key is pressed
            while (!Console.KeyAvailable && !cancellationToken.IsCancellationRequested)
            {
                i++;
                Stopwatch watch = new Stopwatch();
                watch.Start();

                try
                {
                    // Retry the following call according to the policy wrap
                    string msg = await policyWrap.ExecuteAsync <String>(ct =>
                    {
                        // 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.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + i));
                    }, cancellationToken);

                    watch.Stop();

                    // Display the response message on the console
                    ConsoleHelper.WriteInColor("Response : " + msg, ConsoleColor.Green);
                    ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green);

                    eventualSuccesses++;
                }
                catch (BrokenCircuitException b)
                {
                    watch.Stop();
                    ConsoleHelper.WriteInColor("Request " + i + " failed with: " + b.GetType().Name, ConsoleColor.Red);
                    ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red);
                    eventualFailuresDueToCircuitBreaking++;
                }
                catch (Exception e)
                {
                    watch.Stop();
                    ConsoleHelper.WriteInColor("Request " + i + " eventually failed with: " + e.Message, ConsoleColor.Red);
                    ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red);
                    eventualFailuresForOtherReasons++;
                }

                // Wait half second
                await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);
            }

            Console.WriteLine("");
            Console.WriteLine("Total requests made                     : " + i);
            Console.WriteLine("Requests which eventually succeeded     : " + eventualSuccesses);
            Console.WriteLine("Retries made to help achieve success    : " + retries);
            Console.WriteLine("Requests failed early by broken circuit : " + eventualFailuresDueToCircuitBreaking);
            Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons);
        }
예제 #6
0
 public RpdClient(RpdNetworkConfig config)
 {
     this.config = config;
     this.client = new RestClient(config.BaseUrl);
     this.policy = RestPolicy.DefaultPolicy(config.RetryAttempts, config.TimeOut);
 }
예제 #7
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log)
        {
            Guid requestID = Guid.NewGuid();

            try
            {
                log.Info($"LoadPersonGroup was triggered request id {requestID}");
                string largepersongroupid = req.GetQueryNameValuePairs()
                                            .FirstOrDefault(q => string.Compare(q.Key, "groupid", true) == 0)
                                            .Value;
                if (largepersongroupid == null)
                {
                    // Get request body
                    dynamic data = await req.Content.ReadAsAsync <object>();

                    largepersongroupid = data?.groupid;
                }
                if (largepersongroupid != null)
                {
                    string   apis   = ConfigurationManager.AppSettings["apis"];
                    string[] apiArr = apis.Split(',');
                    if (apiArr.Length > 0)
                    {
                        _loadPersonClient = _loadPersonClient ?? new HttpClient();
                        PolicyWrap <HttpResponseMessage> resilientPolicy = FaceHelper.DefineAndRetrieveResiliencyStrategy(log);
                        int i;
                        //setting the map of api to database in database 1
                        IDatabase cache = Connection.GetDatabase(1);
                        for (i = 1; i <= apiArr.Length; i++)
                        {
                            cache.StringSet(apiArr[i - 1], i + 1);
                        }
                        var personResult = new ListPersonGroup(log, _loadPersonClient);
                        for (i = 1; i <= apiArr.Length; i++)
                        {
                            bool   isComplete = false;
                            string lastPerson = string.Empty;
                            Task <InternalPersonDetails[]> task;
                            List <InternalPersonDetails>   personList = new List <InternalPersonDetails>();
                            cache = Connection.GetDatabase(i + 1);
                            while (!isComplete)
                            {
                                task = personResult.GetListPersonGroup(lastPerson, apiArr[i - 1], largepersongroupid, requestID, resilientPolicy);
                                task.Wait();

                                if (task.Result.Length < 1000)
                                {
                                    isComplete = true;
                                }
                                if (task.Result.Length > 0)
                                {
                                    lastPerson = task.Result[task.Result.Length - 1].PersonId.ToString();
                                    personList.AddRange(task.Result.ToList());
                                }

                                int loop = task.Result.Length / 100;
                                var tmplist = task.Result.ToList();
                                int k = 0, len = 0;
                                for (k = 0; k < loop; k++)
                                {
                                    var tmpinnerlist = tmplist.GetRange(k * 100, 100);
                                    len += tmpinnerlist.Count;
                                    cache.StringSet(tmpinnerlist.Select(s =>
                                                                        new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always);
                                }
                                if (tmplist.Count - len > 0)
                                {
                                    var tmpinnerlist = tmplist.GetRange(k * 100, tmplist.Count - len);
                                    cache.StringSet(tmpinnerlist.Select(s =>
                                                                        new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always);
                                }
                            }
                        }
                        return(req.CreateResponse(HttpStatusCode.OK, "Redis loaded successfully"));
                    }
                    else
                    {
                        string msg = "List of Api setting is empty";
                        log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}");
                        return(req.CreateResponse(HttpStatusCode.BadRequest, "List of Api setting is empty"));
                    }
                }
                else
                {
                    string msg = "Please pass a large person group id on the query string or in the request body";
                    log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}");
                    return(req.CreateResponse(HttpStatusCode.BadRequest, msg));
                }
            }
            catch (Exception e)
            {
                log.Error($"Exception-LoadPersonGroup: {e.Message} requestId: {requestID} ticks: {DateTime.Now.Ticks}", e);
                return(req.CreateResponse(HttpStatusCode.BadRequest, e.Message));
            }
        }
 public async Task <InternalPersonDetails[]> GetListPersonGroup(string startPerson, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
 {
     return(await MakeListPersonGroupRequest(startPerson, apiKey, largegroupid, requestId, policy));
 }
예제 #9
0
        public static List <TestUser> GetUsers()
        {
            //Retry untill other side return users successfull,
            //After 3 tries, just return John Doe...
            //Fallback policy -> create John Doe
            PolicyWrap <List <TestUser> > policy = CreateWaitPolicy();
            var users = GetTimeRegistrationDemoUsers();

            users.Wait(50000);

            var testUsers = users.Result.Users.Select(x =>
                                                      new TestUser
            {
                SubjectId = x.Id.ToString(),
                Username  = x.FirstName,
                Password  = x.LastName,
                Claims    = new List <Claim>
                {
                    new Claim("name", x.FirstName + " " + x.LastName),
                    new Claim("role", x.Roles.FirstOrDefault().Id)
                }
            }
                                                      ).ToList();

            return(testUsers);

            //return new List<TestUser>
            //{
            //    new TestUser
            //    {
            //        SubjectId = "50",
            //        Username = "******",
            //        Password = "******",
            //        Claims = new List<Claim>
            //        {
            //            new Claim("name", "jef"),
            //            new Claim("role","Employee")
            //        }
            //    },

            //    new TestUser
            //    {
            //        SubjectId = "1",
            //        Username = "******",
            //        Password = "******",

            //        Claims = new List<Claim>
            //        {
            //            new Claim("name", "alice"),
            //            new Claim("website", "https://alice.com"),
            //            new Claim("role","Administrators")
            //        }
            //    },
            //    new TestUser
            //    {
            //        SubjectId = "2",
            //        Username = "******",
            //        Password = "******",

            //        Claims = new List<Claim>
            //        {
            //            new Claim("name", "bob"),
            //            new Claim("website", "https://bob.com"),
            //            new Claim("role","Managers")
            //        }
            //    }
            //};
        }
예제 #10
0
 public void AddPolicy(string origin, PolicyWrap policy)
 {
 }
예제 #11
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,
                                         // 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;
                }
            }
        }
예제 #13
0
        private async Task <FaceDetectResult[]> MakeFaceDetectRequest(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
        {
            _log.Info($"Making detect request requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}");
            string strResult = string.Empty;

            FaceDetectResult[] result = null;
            // Request parameters.
            const string requestParameters = "returnFaceId=true&returnFaceLandmarks=false";
            // Get the API URL and the API key from settings.
            var uriBase = ConfigurationManager.AppSettings["faceDetectApiUrl"];

            // Configure the HttpClient request headers.
            _client.DefaultRequestHeaders.Clear();
            _client.DefaultRequestHeaders.Accept.Clear();
            _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
            //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            // Assemble the URI for the REST API Call.
            var uri = uriBase + "?" + requestParameters;

            try
            {
                // Execute the REST API call, implementing our resiliency strategy.
                HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetImageHttpContent(imageBytes)));

                // Get the JSON response.
                strResult = await response.Content.ReadAsStringAsync();

                result = await response.Content.ReadAsAsync <FaceDetectResult[]>();

                _log.Info($"detect completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}");
            }
            catch (BrokenCircuitException bce)
            {
                _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce);
            }
            catch (Exception e)
            {
                _log.Error($"Critical error-MakeFaceDetectRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e);
            }

            return(result);
        }
예제 #14
0
 public async Task <FaceDetectResult[]> DetectFaces(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
 {
     return(await MakeFaceDetectRequest(imageBytes, apiKey, requestId, policy));
 }
예제 #15
0
 public CustomersAPIService(HttpClient client, Policy[] resiliencePolicies)
 {
     _client = client;
     _policy = Policy.WrapAsync(resiliencePolicies);
 }
        public static IRestResponse ExecuteWithPolicy(this IRestClient client, IRestRequest request, PolicyWrap policy)
        {
            // capture the exception so we can push it though the standard response flow.
            PolicyResult <IRestResponse> val = policy.ExecuteAndCapture(() => client.Execute(request));

            IRestResponse restResponse = val.Result;

            if (restResponse == null)
            {
                restResponse = new RestResponse
                {
                    Request        = request,
                    ErrorException = val.FinalException
                };
            }

            return(restResponse);
        }
예제 #17
0
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            Log.Logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day)
                         .CreateLogger();

            _circuitBreakerPolicy = Policy.Handle <HttpRequestException>()
                                    .CircuitBreaker(
                // number of exceptions before breaking circuit
                5,
                // time circuit opened before retry
                TimeSpan.FromMinutes(1),
                (exception, duration) =>
            {
                // on circuit opened
                Log.Information("Circuit breaker opened");
            },
                () =>
            {
                // on circuit closed
                Log.Information("Circuit breaker reset");
            });



            _retryPolicy = Policy.Handle <HttpRequestException>()
                           .WaitAndRetry(
                // number of retries
                4,
                // exponential backofff
                retryAttempt => TimeSpan.FromSeconds(retryAttempt),
                // on retry
                (exception, timeSpan, retryCount, context) =>
            {
                var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
                          $"of {context.PolicyKey} " +
                          $"at {context.ExecutionKey}";
                Log.Warning(msg);
            });

            // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken.
            FallbackPolicy <UserPayload> fallbackForCircuitBreaker = Policy <UserPayload>
                                                                     .Handle <BrokenCircuitException>()
                                                                     .Fallback(
                fallbackValue: new UserPayload {
                Users = null, ErrorMessage = "Please try again later [Fallback for broken circuit]"
            },
                onFallback: b =>
            {
                Log.Information("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red);
            }
                );

            // Define a fallback policy: provide a substitute string to the user, for any exception.
            FallbackPolicy <UserPayload> fallbackForAnyException = Policy <UserPayload>
                                                                   .Handle <Exception>()
                                                                   .Fallback(
                fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return(new UserPayload {
                    Users = null, ErrorMessage = "Please try again later [Fallback for any exception]"
                }); },
                onFallback: e =>
            {
                Log.Information("Fallback catches failed with: " + e.Exception.Message, ConsoleColor.DarkMagenta);
            }
                );

            PolicyWrap myResilienceStrategy     = Policy.Wrap(_retryPolicy, _circuitBreakerPolicy);
            PolicyWrap <UserPayload> policyWrap = fallbackForAnyException.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy));

            LoopCalls(policyWrap);
        }
 public ResilientHttpClient(ILogger logger)
 {
     this.logger   = logger;
     policyWrapper = Policy.WrapAsync(CreatePolicies());
 }
        private async Task <InternalPersonDetails[]> MakeListPersonGroupRequest(string startPerson, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
        {
            string strResult = string.Empty;

            _log.Info($"Making ListPerson GET request requestId: {requestId} apiKey:{apiKey} start person {startPerson} ticks: {DateTime.Now.Ticks}");
            InternalPersonDetails[] result = null;
            // Request parameters.
            string requestParameters = largegroupid + "/persons";
            // Get the API URL and the API key from settings.
            var uriBase = ConfigurationManager.AppSettings["facePersonApiUrl"];

            // Configure the HttpClient request headers.
            _client.DefaultRequestHeaders.Clear();
            _client.DefaultRequestHeaders.Accept.Clear();
            _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
            // Assemble the URI for the REST API Call.
            var uri = uriBase + "/" + requestParameters;

            if (startPerson != string.Empty)
            {
                uri += "?start=" + startPerson;
            }
            try
            {
                // Execute the REST API call, implementing our resiliency strategy.
                HttpResponseMessage response = await policy.ExecuteAsync(() => _client.GetAsync(uri));

                // Get the JSON response.
                strResult = await response.Content.ReadAsStringAsync();

                result = await response.Content.ReadAsAsync <InternalPersonDetails[]>();

                _log.Info($"ListPersonGroup completed: requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}");
            }
            catch (BrokenCircuitException bce)
            {
                _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce);
            }
            catch (Exception e)
            {
                _log.Error($"Critical error-MakeListPersonGroupRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e);
            }

            return(result);
        }
 public ResilientHttpClient(Policy[] policies, ILogger logger)
 {
     this.logger = logger;
     // Add Policies to be applied
     policyWrapper = Policy.WrapAsync(policies);
 }
예제 #21
0
        public static async Task <bool> RunDetect(Guid requestID, string apis, string name, string source,
                                                  Stream incomingPicture, string sourceContainerName, string resultContainerName, IAsyncCollector <object> outputItem, TraceWriter log, string videoName = null)
        {
            string apikey = string.Empty;

            try
            {
                string[] apiArr    = apis.Split(',');
                int      randomApi = FaceHelper.Instance.Next(0, apiArr.Length);
                apikey = apiArr[randomApi];
                log.Info($"RunDetect request id: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}");
                Tuple <HttpClient, PolicyWrap <HttpResponseMessage> > tuple = FaceHelper.HttpClientList.GetOrAdd(apikey, new Tuple <HttpClient, PolicyWrap <HttpResponseMessage> >(
                                                                                                                     new HttpClient(),
                                                                                                                     FaceHelper.DefineAndRetrieveResiliencyStrategy(log)));
                HttpClient client = tuple.Item1;
                PolicyWrap <HttpResponseMessage> policy = tuple.Item2;
                IDatabase cache = FaceHelper.Connection.GetDatabase(int.Parse(FaceHelper.Connection.GetDatabase(1).StringGet(apikey)));

                //the large group id it's based on the mac address we get - each MAC address can work with different face api group
                string largegroupid = ConfigurationManager.AppSettings[source];
                if (videoName == null)
                {
                    log.Info($"Detecting {name} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}");
                }
                else
                {
                    log.Info($"Detecting thumbnail {name} from {videoName} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}");
                }
                byte[] pictureImage;
                // Convert the incoming image stream to a byte array.
                using (var br = new BinaryReader(incomingPicture))
                {
                    pictureImage = br.ReadBytes((int)incomingPicture.Length);
                }
                var detectionResult = await new FaceDetect(log, client).DetectFaces(pictureImage, apikey, requestID, policy);
                if ((detectionResult != null) && (detectionResult.Length > 0))
                {
                    //prepare identify request
                    int    maxCandidate     = int.Parse(ConfigurationManager.AppSettings["maxNumOfCandidatesReturned"]);
                    double threshold        = double.Parse(ConfigurationManager.AppSettings["confidenceThreshold"]);
                    var    identifyResquest = new FaceIdentifyRequest()
                    {
                        ConfidenceThreshold        = threshold,
                        MaxNumOfCandidatesReturned = maxCandidate,
                        LargePersonGroupId         = largegroupid,
                        FaceIds = detectionResult.Select(s => s.FaceId).ToArray()
                    };
                    var identifyResult = await new FaceIdentify(log, client).IdentifyFaces(identifyResquest, apikey, requestID, policy);
                    if ((identifyResult == null) || (identifyResult.Length == 0))
                    {
                        log.Info($"No identification result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}");
                    }
                    var personResult = new PersonDetails(log, client);
                    //merging results and find person name
                    for (int i = 0; i < detectionResult.Length; i++)
                    {
                        if (videoName == null)
                        {
                            detectionResult[i].FaceBlobName = string.Concat(detectionResult[i].FaceId, "_", name);
                        }
                        else
                        {
                            detectionResult[i].FaceBlobName = videoName + "/" + name;
                        }
                        if ((identifyResult != null) && (identifyResult.Length > 0))
                        {
                            detectionResult[i].Candidates = identifyResult[i].Candidates;
                            for (int j = 0; j < detectionResult[i].Candidates.Length; j++)
                            {
                                string personid   = detectionResult[i].Candidates[j].PersonId.ToString();
                                string personName = cache.StringGet(largegroupid + "-" + personid);
                                if (string.IsNullOrEmpty(personName) == true)
                                {
                                    log.Info($"Missing cache requestId: {requestID} apiKey: {apikey} personId: {personid} ticks: {DateTime.Now.Ticks}");
                                    var tPerson = await personResult.GetPersonName(personid, apikey, largegroupid, requestID, policy);

                                    personName = tPerson.Name;
                                    cache.StringSet(largegroupid + "-" + personid, personName, null, When.Always);
                                }
                                detectionResult[i].Candidates[j].PersonName = new InternalPersonDetails()
                                {
                                    PersonId = detectionResult[i].Candidates[j].PersonId,
                                    Name     = personName
                                };
                            }
                        }
                    }
                }
                else
                {
                    log.Info($"No dectection result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}");
                    //in case of video, we want to create a link to the face detected by AMS (Azure Media Services) although face api didn't recognize it
                    if (videoName != null)
                    {
                        detectionResult = new FaceDetectResult[1] {
                            new FaceDetectResult()
                            {
                                FaceBlobName = videoName + "/" + name
                            }
                        }
                    }
                    ;
                }
                string blobname     = videoName ?? name;
                var    actionResult = new FaceIdentifyResult()
                {
                    BlobName            = blobname,
                    ContainerName       = sourceContainerName,
                    ResultContainerName = resultContainerName,
                    BlobLength          = incomingPicture.Length,
                    CreatedDateTime     = DateTime.UtcNow,
                    RequestId           = requestID,
                    ApiKey           = apikey,
                    LargeGroupId     = largegroupid,
                    Source           = source,
                    DetectResultList = detectionResult
                };
                string strResult = JsonConvert.SerializeObject(actionResult);
                await outputItem.AddAsync(strResult);
            }
            catch (Exception ex)
            {
                log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}", ex);
                return(false);
            }
            return(true);
        }
        public PollyServiceClient()
        {
            _client     = new HttpClient();
            _gatewayUri = _primaryUri;

            var circuitBreakerPolicy = Policy
                                       .Handle <Exception>()
                                       .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 4,
                durationOfBreak: TimeSpan.FromSeconds(3),
                onBreak: (ex, breakDelay) =>
            {
                //Called when circuit first open
                //Setting the backupUri so calls now go to backup gateway
                _gatewayUri = _backupUri;
            },
                onReset: () =>
            {
                //Called when circuit is closed again.
                //Primary gateway is responding again, setting to primaryUri.
                _gatewayUri = _primaryUri;
            },
                onHalfOpen: () =>
            {
                //Called when the policy is going to check the original call to see if there are no exceptions.
                //Send the call to the primary gateway to see if it's operational again.
                _gatewayUri = _primaryUri;;
            }
                );

            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering!  We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromMilliseconds(200),
                (exception, calculatedWaitDuration) =>
            {
                //Handle the exception here.
            });

            FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String>
                                                                .Handle <BrokenCircuitException>()
                                                                .FallbackAsync(
                fallbackAction: /* Demonstrates fallback action/func syntax */ async ct =>
            {
                await Task.FromResult(true);

                //This is called after the circuit breaker is tripped
                //and the gatewayUri is changed to point to the backup
                //gateway.  This call runs on the backup gateway.
                return(await ClientWrapper());
            },
                onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
            }
                );

            //Something really bad has happened.
            FallbackPolicy <String> fallbackForAnyException = Policy <String>
                                                              .Handle <Exception>()
                                                              .FallbackAsync(
                fallbackAction: /* Demonstrates fallback action/func syntax */ async ct =>
            {
                await Task.FromResult(true);
                return("Another exception occurred.");
            },
                onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
            }
                );

            PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy);

            _policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy));
        }
예제 #23
0
        public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress)
        {
            if (cancellationToken == null)
            {
                throw new ArgumentNullException(nameof(cancellationToken));
            }
            if (progress == null)
            {
                throw new ArgumentNullException(nameof(progress));
            }

            // Let's call a web api service to make repeated requests to a server.
            // The service is programmed to fail after 3 requests in 5 seconds.

            eventualSuccesses = 0;
            retries           = 0;
            eventualFailuresDueToCircuitBreaking = 0;
            eventualFailuresForOtherReasons      = 0;

            progress.Report(ProgressWithMessage(typeof(AsyncDemo08_Wrap_Fallback_WaitAndRetry_CircuitBreaker).Name));
            progress.Report(ProgressWithMessage("======"));
            progress.Report(ProgressWithMessage(String.Empty));

            Stopwatch watch = null;

            // Define our waitAndRetry policy: keep retrying with 200ms gaps.
            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering!  We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromMilliseconds(200),
                (exception, calculatedWaitDuration) =>
            {
                progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow));
                retries++;
            });

            // Define our CircuitBreaker policy: Break if the action fails 4 times in a row.
            var circuitBreakerPolicy = Policy
                                       .Handle <Exception>()
                                       .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 4,
                durationOfBreak: TimeSpan.FromSeconds(3),
                onBreak: (ex, breakDelay) =>
            {
                progress.Report(ProgressWithMessage(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta));
                progress.Report(ProgressWithMessage("..due to: " + ex.Message, Color.Magenta));
            },
                onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Call ok! Closed the circuit again!", Color.Magenta)),
                onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: Next call is a trial!", Color.Magenta))
                );

            // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken.
            FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String>
                                                                .Handle <BrokenCircuitException>()
                                                                .FallbackAsync(
                fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [message substituted by fallback policy]",
                onFallbackAsync: async b =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message
                                                    + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresDueToCircuitBreaking++;
            }
                );

            // Define a fallback policy: provide a substitute string to the user, for any exception.
            FallbackPolicy <String> fallbackForAnyException = Policy <String>
                                                              .Handle <Exception>()
                                                              .FallbackAsync(
                fallbackAction: /* Demonstrates fallback action/func syntax */ async ct =>
            {
                await Task.FromResult(true);
                /* do something else async if desired */
                return("Please try again later [Fallback for any exception]");
            },
                onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message
                                                    + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresForOtherReasons++;
            }
                );

            // As demo07: we combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax.
            PolicyWrap myResilienceStrategy = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy);

            // Added in demo08: we wrap the two fallback policies onto the front of the existing wrap too.  Demonstrates the *instance* wrap syntax. And the fact that the PolicyWrap myResilienceStrategy from above is just another Policy, which can be onward-wrapped too.
            // With this pattern, you can build an overall resilience strategy programmatically, reusing some common parts (eg PolicyWrap myResilienceStrategy) but varying other parts (eg Fallback) individually for different calls.
            PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy));

            // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.WrapAsync(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy);

            totalRequests = 0;

            using (var client = new HttpClient())
            {
                bool internalCancel = false;
                // Do the following until a key is pressed
                while (!internalCancel && !cancellationToken.IsCancellationRequested)
                {
                    totalRequests++;
                    watch = new Stopwatch();
                    watch.Start();

                    try
                    {
                        // Manage the call according to the whole policy wrap
                        string response = await policyWrap.ExecuteAsync(ct =>
                                                                        client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken);

                        watch.Stop();

                        // Display the response message on the console
                        progress.Report(ProgressWithMessage("Response : " + response + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green));

                        eventualSuccesses++;
                    }
                    catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>.  It's only been left in to *demonstrate* it should never get hit.
                    {
                        throw new InvalidOperationException("Should never arrive here.  Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e);
                    }

                    // Wait half second
                    await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);

                    internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable;
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="T:EasyCaching.HybridCache.HybridCachingProvider"/> class.
        /// </summary>
        /// <param name="name">Name.</param>
        /// <param name="optionsAccs">Options accs.</param>
        /// <param name="factory">Providers factory</param>
        /// <param name="bus">Bus.</param>
        /// <param name="loggerFactory">Logger factory.</param>
        public HybridCachingProvider(
            string name
            , HybridCachingOptions optionsAccs
            , IEasyCachingProviderFactory factory
            , IEasyCachingBus bus          = null
            , ILoggerFactory loggerFactory = null
            )
        {
            ArgumentCheck.NotNull(factory, nameof(factory));

            this._name    = name;
            this._options = optionsAccs;

            ArgumentCheck.NotNullOrWhiteSpace(_options.TopicName, nameof(_options.TopicName));

            this._logger = loggerFactory?.CreateLogger <HybridCachingProvider>();

            // Here use the order to distinguish traditional provider
            var local = factory.GetCachingProvider(_options.LocalCacheProviderName);

            if (local.IsDistributedCache)
            {
                throw new NotFoundCachingProviderException("Can not found any local caching providers.");
            }
            else
            {
                this._localCache = local;
            }

            // Here use the order to distinguish traditional provider
            var distributed = factory.GetCachingProvider(_options.DistributedCacheProviderName);

            if (!distributed.IsDistributedCache)
            {
                throw new NotFoundCachingProviderException("Can not found any distributed caching providers.");
            }
            else
            {
                this._distributedCache = distributed;
            }

            this._bus = bus ?? NullEasyCachingBus.Instance;
            this._bus.Subscribe(_options.TopicName, OnMessage);

            this._cacheId = Guid.NewGuid().ToString("N");


            // policy

            retryAsyncPolicy = Policy.Handle <Exception>()
                               .WaitAndRetryAsync(this._options.BusRetryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt - 1)));

            retryPolicy = Policy.Handle <Exception>()
                          .WaitAndRetry(this._options.BusRetryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt - 1)));

            fallbackPolicy = Policy.Handle <Exception>().Fallback(() => { });

            fallbackAsyncPolicy = Policy.Handle <Exception>().FallbackAsync(ct =>
            {
                return(Task.CompletedTask);
            });

            _busSyncWrap  = Policy.Wrap(fallbackPolicy, retryPolicy);
            _busAsyncWrap = Policy.WrapAsync(fallbackAsyncPolicy, retryAsyncPolicy);
        }
        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);
        }
예제 #26
0
 public async Task <InternalPersonDetails> GetPersonName(string personId, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy)
 {
     return(await MakePersonNameRequest(personId, apiKey, largegroupid, requestId, policy));
 }
        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 override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress)
        {
            if (cancellationToken == null)
            {
                throw new ArgumentNullException(nameof(cancellationToken));
            }
            if (progress == null)
            {
                throw new ArgumentNullException(nameof(progress));
            }

            // Let's call a web api service to make repeated requests to a server.
            // The service is programmed to fail after 3 requests in 5 seconds.

            eventualSuccesses = 0;
            retries           = 0;
            eventualFailuresDueToCircuitBreaking = 0;
            eventualFailuresForOtherReasons      = 0;

            progress.Report(ProgressWithMessage(typeof(AsyncDemo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name));
            progress.Report(ProgressWithMessage("======"));
            progress.Report(ProgressWithMessage(String.Empty));

            // Define our waitAndRetry policy: keep retrying with 200ms gaps.
            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering!  We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromMilliseconds(200),
                (exception, calculatedWaitDuration) =>
            {
                // This is your new exception handler!
                // Tell the user what they've won!
                progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow));
                retries++;
            });

            // Define our CircuitBreaker policy: Break if the action fails 4 times in a row.
            var circuitBreakerPolicy = Policy
                                       .Handle <Exception>()
                                       .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 4,
                durationOfBreak: TimeSpan.FromSeconds(3),
                onBreak: (ex, breakDelay) =>
            {
                progress.Report(ProgressWithMessage(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta));
                progress.Report(ProgressWithMessage("..due to: " + ex.Message, Color.Magenta));
            },
                onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Call ok! Closed the circuit again!", Color.Magenta)),
                onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: Next call is a trial!", Color.Magenta))
                );

            // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap.
            PolicyWrap policyWrap = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy);

            using (var client = new HttpClient())
            {
                totalRequests = 0;
                bool internalCancel = false;
                // 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 = await policyWrap.ExecuteAsync <String>(ct =>
                        {
                            // 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.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests));
                        }, cancellationToken);

                        watch.Stop();

                        // Display the response message on the console
                        progress.Report(ProgressWithMessage("Response : " + response
                                                            + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green));

                        eventualSuccesses++;
                    }
                    catch (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
                    await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);

                    internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable;
                }
            }
        }
예제 #29
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOptions();
            services.AddApiVersioning(
                o =>
            {
                o.AssumeDefaultVersionWhenUnspecified = true;
                o.DefaultApiVersion = new ApiVersion(1, 0);
            });

            var azureStorageSettings        = GetSettings <AzureStorageSettings>();
            var notificationServiceSettings = GetSettings <NotificationServiceSettings>();
            var faultToleranceSettings      = GetSettings <FaultToleranceSettings>();

            services.AddSingleton <IMetricsClient>(context =>
            {
                var metricsClientFactory = new MetricsClientFactory(context.GetRequiredService <ILoggerFactory>(),
                                                                    TimeSpan.FromSeconds(15));
                return(metricsClientFactory.CreateMetricsClient <LoggerMetricsClient>());
            });

            TimeoutPolicy        timeoutPolicy        = Policy.Timeout(faultToleranceSettings.TimeoutLength, TimeoutStrategy.Pessimistic);
            CircuitBreakerPolicy circuitBreakerPolicy = Policy
                                                        .Handle <Exception>()
                                                        .CircuitBreaker(
                exceptionsAllowedBeforeBreaking: faultToleranceSettings.ExceptionsAllowedBeforeBreaking,
                durationOfBreak: TimeSpan.FromMinutes(faultToleranceSettings.DurationOfBreakInMinutes)
                );
            PolicyWrap policyWrap = Policy.Wrap(circuitBreakerPolicy, timeoutPolicy);

            services.AddSingleton <ISyncPolicy>(policyWrap);

            QueueClient queueClient = new QueueClient(notificationServiceSettings.ServiceBusConnectionString,
                                                      notificationServiceSettings.QueueName);
            ServiceBusNotificationServiceClient notificationService = new ServiceBusNotificationServiceClient(queueClient);

            services.AddSingleton <INotificationService>(context =>
                                                         new NotificationServiceMetricsDecorator(
                                                             new NotificationServiceFaultToleranceDecorator(
                                                                 notificationService,
                                                                 context.GetRequiredService <ISyncPolicy>()),
                                                             context.GetRequiredService <IMetricsClient>()));

            AzureCloudTable        profileCloudTable = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.ProfilesTableName);
            AzureTableProfileStore profileStore      = new AzureTableProfileStore(profileCloudTable);

            services.AddSingleton <IProfileStore>(context =>
                                                  new ProfileStoreMetricsDecorator(
                                                      new ProfileStoreFaultToleranceDecorator(
                                                          profileStore,
                                                          context.GetRequiredService <ISyncPolicy>()),
                                                      context.GetRequiredService <IMetricsClient>()));

            AzureCloudTable         messagesCloudTable = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.MessagesTableName);
            AzureTableMessagesStore messagesStore      = new AzureTableMessagesStore(messagesCloudTable);

            services.AddSingleton <IMessagesStore>(context =>
                                                   new MessagesStoreMetricsDecorator(
                                                       new MessagesStoreFaultToleranceDecorator(
                                                           messagesStore,
                                                           context.GetRequiredService <ISyncPolicy>()),
                                                       context.GetRequiredService <IMetricsClient>()));

            AzureCloudTable conversationsCloudTable         = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.UsersTableName);
            AzureTableConversationsStore conversationsStore = new AzureTableConversationsStore(conversationsCloudTable, messagesStore);

            services.AddSingleton <IConversationsStore>(context =>
                                                        new ConversationStoreMetricsDecorator(
                                                            new ConversationsStoreFaultToleranceDecorator(
                                                                conversationsStore,
                                                                context.GetRequiredService <ISyncPolicy>()),
                                                            context.GetRequiredService <IMetricsClient>()));

            services.AddSingleton <IConversationService>(context =>
                                                         new ConversationServiceMetricsDecorator(
                                                             new ConversationService(
                                                                 context.GetRequiredService <IConversationsStore>(),
                                                                 context.GetRequiredService <ILogger <ConversationService> >(),
                                                                 context.GetRequiredService <INotificationService>()),
                                                             context.GetRequiredService <IMetricsClient>()));

            services.AddLogging();
            services.AddMvc();
        }
        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);
        }