Ejemplo n.º 1
0
        public CatalogController()
        {
            _timeoutPolicy = Policy.TimeoutAsync(1, onTimeoutAsync: TimeoutDelegate);

            _httpRetryPolicy =
                Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                .Or <TimeoutRejectedException>()
                .RetryAsync(3, onRetry: HttpRetryPolicyDelegate);

            _httpRequestFallbackPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                                         .Or <TimeoutRejectedException>()
                                         .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ObjectContent(_cachedResult.GetType(), _cachedResult, new JsonMediaTypeFormatter())
            }, onFallbackAsync: HttpRequestFallbackPolicyDelegate);

            _policyWrap = _httpRequestFallbackPolicy.WrapAsync(_httpRetryPolicy.WrapAsync(_timeoutPolicy));
        }
        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;
                }
            }
        }
Ejemplo n.º 3
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;
                }
            }
        }
        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));
        }