Example #1
0
        public HAPublisher(IPublisher primaryPublisher, IPublisher secondaryPublisher)
        {
            this.primaryPublisher   = primaryPublisher;
            this.secondaryPublisher = secondaryPublisher;

            this.exponentialRetryPolicy = Policy
                                          .Handle <TimeoutException>()
                                          .WaitAndRetryAsync(
                2,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                (exception, timeSpan, context) => {
                Logger.Log(string.Format("Retry for ex={0}", exception.GetType().Name), LoggerState.Warning);
            });

            this.circuitBreakerPolicy = Policy.Handle <Exception>().CircuitBreakerAsync(
                2,
                TimeSpan.FromSeconds(20),
                (context, ts) => { Logger.Log("CircuitBreaker Closed to Open", LoggerState.Warning); },
                () => { Logger.Log("CircuitBreaker Reset", LoggerState.Warning); });

            this.fallbackPolicy = Policy
                                  .Handle <Exception>()
                                  .FallbackAsync(async(ctx, ct) => {
                await this.PublishSecondaryAsync(ctx["message"].ToString());
            }, async(ex, ctx) => {
                Logger.Log(string.Format("Executing fallback for Ex={0}", ex.GetType().Name), LoggerState.Warning);
                await Task.FromResult(0);
            });
        }
        public WaitRetryDelegateTimeoutService()
        {
            httpClient.BaseAddress = new Uri("https://localhost:44354/");
            httpClient.Timeout     = new TimeSpan(0, 0, 30);
            httpClient.DefaultRequestHeaders.Clear();

            httpWaitAndRetry = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                               .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) / 2));

            // this is not the same as setting timeout for HttpClient
            // if the request does not respond in the given time (ex. 5 seconds), TimeoutRejectedException is thrown
            timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(5, TimeoutStrategy.Pessimistic);

            httpretryPolicyForHttpClienTimeout = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                                                 .Or <HttpRequestException>()
                                                 .RetryAsync(1, onRetry: OnRetry);

            httpWaitAndRetryWithDelegate = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                                           .WaitAndRetryAsync(3, retryAttempt =>
                                                              TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) / 2), onRetry: (httpResponseMessage, retryCount) =>
            {
                // Log
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"Request failed...{httpResponseMessage.Result.StatusCode}");

                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine($"Retrying...");
                Console.ForegroundColor = ConsoleColor.White;
            });

            httpFallbackPolicy = Policy.HandleResult <HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)
                                 .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
            {
            });
        }
        public HomeController(ILogger <HomeController> logger)
        {
            _logger      = logger;
            _retryPolicy = Policy.HandleResult <HttpResponseMessage>(result =>
                                                                     !result.IsSuccessStatusCode).RetryAsync(5, (a, b) => {
                _logger.LogInformation("Retry");
            });

            _circuitBreakerPolicy = Policy.HandleResult <HttpResponseMessage>
                                        (r => !r.IsSuccessStatusCode).Or <HttpRequestException>()
                                    .CircuitBreakerAsync(2, TimeSpan.FromSeconds(10),
                                                         (d, c) => {
                string a = "Break";
            },
                                                         () => {
                string a = "Rest";
            },
                                                         () => {
                string a = "Half";
            }
                                                         );


            _fallbackPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                              .Or <BrokenCircuitException>()
                              .FallbackAsync(new HttpResponseMessage(System.Net.HttpStatusCode.OK)
            {
                Content = new ObjectContent(typeof(Message), new Message
                {
                    Id   = 100,
                    Text = "Default Text"
                }, new JsonMediaTypeFormatter())
            });
        }
        public ProxyController(IHttpClientFactory httpClientFactory)
        {
            _fallbackPolicy = Policy <IActionResult>
                              .Handle <Exception>()
                              .FallbackAsync(Content("Sorry, we are currently experiencing issues. Please try again later"));

            _retryPolicy = Policy <IActionResult>
                           .Handle <Exception>()
                           .RetryAsync();

            if (_circuitBreakerPolicy == null)
            {
                _circuitBreakerPolicy = Policy
                                        .Handle <Exception>()
                                        .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));
            }

            _policy = Policy <IActionResult>
                      .Handle <Exception>()
                      .FallbackAsync(Content("Sorry, we are currently experiencing issues. Please try again later"))
                      .WrapAsync(_retryPolicy)
                      .WrapAsync(_circuitBreakerPolicy);

            _httpClient = httpClientFactory.CreateClient();
        }
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            //一个HystrixCommand中保持一个policy对象即可
            //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象
            //根据反射原理,同一个方法的MethodInfo是同一个对象,但是对象上取出来的HystrixCommandAttribute
            //每次获取的都是不同的对象,因此以MethodInfo为Key保存到policies中,确保一个方法对应一个policy实例
            policies.TryGetValue(context.ServiceMethod, out IAsyncPolicy policy);
            lock (policies)//因为Invoke可能是并发调用,因此要确保policies赋值的线程安全
            {
                if (policy == null)
                {
                    policy = Policy.NoOpAsync();

                    if (EnableCircuitBreaker)
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak)));
                    }
                    if (TimeOutMilliseconds > 0)
                    {
                        policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic));
                    }
                    if (MaxRetryTimes > 0)
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds)));
                    }
                    if (EnableFallBack)
                    {
                        AsyncFallbackPolicy policyFallBack = Policy
                                                             .Handle <Exception>()
                                                             .FallbackAsync(async(ctx, t) =>
                        {
                            AspectContext aspectContext = (AspectContext)ctx["aspectContext"];
                            //var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod);
                            //merge this issue: https://github.com/yangzhongke/RuPeng.HystrixCore/issues/2
                            var fallBackMethod    = context.ImplementationMethod.DeclaringType.GetMethod(this.FallBackMethod);
                            Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters);
                            //不能如下这样,因为这是闭包相关,如果这样写第二次调用Invoke的时候context指向的
                            //还是第一次的对象,所以要通过Polly的上下文来传递AspectContext
                            //context.ReturnValue = fallBackResult;
                            aspectContext.ReturnValue = fallBackResult;
                        }, async(ex, t) => { });

                        policy = policyFallBack.WrapAsync(policy);
                    }

                    //放入
                    policies.TryAdd(context.ServiceMethod, policy);
                }
            }

            //把本地调用的AspectContext传递给Polly,主要给FallbackAsync中使用,避免闭包的坑
            Context pollyCtx = new Context();

            pollyCtx["aspectContext"] = context;

            await policy.ExecuteAsync(ctx => next(context), pollyCtx);
        }
        public static void Build(IPolicyRegistry <string> registry)
        {
            //PolicyRegistry registry = new PolicyRegistry();
            //Basic Retry Policy
            AsyncRetryPolicy <HttpResponseMessage> basicRetryPolicy =
                Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                .RetryAsync(2);

            registry.Add(BasicRetryPolicy, basicRetryPolicy);


            //Wait and Retry Policy
            AsyncRetryPolicy <HttpResponseMessage> waitAndRetryPolicy =
                Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromMilliseconds(100 * retryAttempt), onRetryAsync: WaitAndRetryHandler);

            registry.Add(WaitAndRetryPolicy, waitAndRetryPolicy);


            ////Retry Policy with onRetryAsync Delegate
            AsyncRetryPolicy <HttpResponseMessage> retryWithDelegatePolicy =
                Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                .RetryAsync(2, onRetryAsync: OnRetry);

            registry.Add(RetryWithDelegatePolicy, retryWithDelegatePolicy);


            ////Retry Policy or HttpRequestException along with onRetryAsync Delegate
            AsyncRetryPolicy <HttpResponseMessage> retryOrExceptionPolicy =
                Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                .Or <HttpRequestException>()
                .RetryAsync(2, onRetryAsync: OnRetry);

            registry.Add(RetryOrExceptionPolicy, retryOrExceptionPolicy);


            //Fallback Policy
            AsyncFallbackPolicy <HttpResponseMessage> asyncFallbackPolicy =
                Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                .Or <TimeoutRejectedException>()
                .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ObjectContent(typeof(int), int.MaxValue, new JsonMediaTypeFormatter())
            }, onFallbackAsync: FallbackAsyncHandler);

            registry.Add(FallbackWithTimedOutExceptionPolicy, asyncFallbackPolicy);


            //TimeoutPolicy
            AsyncTimeoutPolicy <HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(1, onTimeoutAsync: TimeoutAsyncHandler);

            registry.Add(TimeoutPolicy, timeoutPolicy);
        }
Example #7
0
        public CatalogController()
        {
            _httpRetryPolicy = Policy
                               .HandleResult <HttpResponseMessage>(response => !response.IsSuccessStatusCode)
                               .RetryAsync(3);

            _httpFallbackPolicy = Policy
                                  .HandleResult <HttpResponseMessage>(response => response.StatusCode == HttpStatusCode.InternalServerError)
                                  .FallbackAsync(
                new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ObjectContent(_cachedResult.GetType(), _cachedResult, new JsonMediaTypeFormatter())
            }
                );
        }
        public CircuitBreakerController(IHttpClientFactory httpClientFactory, Summary summary)
        {
            _httpClientFactory = httpClientFactory;
            _summary           = summary;

            fallbackForCircuit = Policy <String>
                                 .Handle <BrokenCircuitException>()
                                 .FallbackAsync(
                fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for broken circuit]",
                onFallbackAsync: async b =>
            {
                System.Threading.Thread.Sleep(200);
                Console.WriteLine("circuit breaker open");
            }
                );
        }
Example #9
0
 public HomeController()
 {
     _retryPolicy = Policy
                    .HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                    .RetryAsync(5, (d, c)
                                => { string a = "retry"; });
     _fallbackPolicy = Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                       .Or <BrokenCircuitException>()
                       .FallbackAsync(new HttpResponseMessage(System.Net.HttpStatusCode.OK)
     {
         Content = new ObjectContent(typeof(Message), new Message
         {
             Id   = 100,
             Text = "لطفا 10 ثانیه منتظر باشید"
         }, new JsonMediaTypeFormatter())
     });
 }
Example #10
0
        public static AsyncPolicy GeneratePublishedIndexSearch(int retries = 15, TimeSpan?timespan = null)
        {
            var waitAndRetryPolicy =
                Policy.Handle <CloudException>(c => c.Message == "Another indexer invocation is currently in progress; concurrent invocations not allowed.")
                .WaitAndRetryAsync(retries, i => timespan ?? TimeSpan.FromSeconds(20));

            AsyncFallbackPolicy fault = Policy.Handle <CloudException>()
                                        .FallbackAsync((cancellationToken) => Task.CompletedTask,
                                                       onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
            });

            AsyncPolicyWrap policyWrap = fault.WrapAsync(waitAndRetryPolicy);

            return(policyWrap);
        }
Example #11
0
        public CatalogController()
        {
            _timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(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 = Policy.WrapAsync(_httpRequestFallbackPolicy, _httpRetryPolicy, _timeoutPolicy);
        }
Example #12
0
        private async Task <ApiResponse <T> > ExecuteApiFunc <T>(Func <Task <ApiResponse <T> > > apifunc)
        {
            AsyncRetryPolicy retryPolicy = Policy
                                           .Handle <ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
                                           .RetryAsync(NUMBER_OF_RETRIES, async(exception, retryCount) => await Task.Delay(500).ConfigureAwait(false));

            AsyncRetryPolicy unauthorizedPolicy = Policy
                                                  .Handle <ApiException>(ex => ex.StatusCode == HttpStatusCode.Unauthorized)
                                                  .RetryAsync(async(exception, retryCount) => await AuthenticationTask().ConfigureAwait(false));

            AsyncFallbackPolicy fallbackPolicy = Policy
                                                 .Handle <Exception>()
                                                 .FallbackAsync(async(cancellationToken) => await FallBackTask().ConfigureAwait(false));

            return(await fallbackPolicy
                   .WrapAsync(unauthorizedPolicy)
                   .WrapAsync(retryPolicy)
                   .ExecuteAsync(async() => await apifunc().ConfigureAwait(false))
                   .ConfigureAwait(false));
        }
Example #13
0
        public CatalogController()
        {
            // throws TimeoutRejectedException if timeout of 1 second is exceeded.
            _httpTimeoutPolicy = Policy.TimeoutAsync(1);

            _httpRetryPolicy = Policy
                               .HandleResult <HttpResponseMessage>(response => !response.IsSuccessStatusCode)
                               .Or <TimeoutRejectedException>()
                               .RetryAsync(3);

            _httpFallbackPolicy = Policy
                                  .HandleResult <HttpResponseMessage>(response => !response.IsSuccessStatusCode)
                                  .Or <TimeoutRejectedException>()
                                  .FallbackAsync(
                new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ObjectContent(_cachedResult.GetType(), _cachedResult, new JsonMediaTypeFormatter())
            }
                );
        }
Example #14
0
    public CatalogController()
    {
        //simple retry
        // _httpRetryPolicy = Policy
        // .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        // .RetryAsync(3);

        //simple retry includes timeout
        _httpRetryPolicy = Policy
                           .HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                           .Or <HttpRequestException>()
                           .Or <TimeoutRejectedException>()
                           .RetryAsync(3, onRetry);

        //simpley retry com funcao quando fail pre retry
        // _httpRetryPolicy = Policy
        // .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        // .RetryAsync(3, (res, retryCounter) =>
        // {
        //     if(res.Result.StatusCode == System.Net.HttpStatusCode.Unauthorized) {
        //         _httpClient = GetHttpClientWithCookie();

        //     }
        // });

        //backoff retry
        //aumenta o delay para o retry por potencia
        // _httpRetryPolicy = Policy
        // .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        // .WaitAndRetryAsync(3, retryTime => TimeSpan.FromSeconds(Math.Pow(2, retryTime) / 2));

        //fallback (cached values on req fails)
        _fallbackPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                          .Or <TimeoutRejectedException>()
                          .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent("99")
        });

        _timeoutPolicy = Policy.TimeoutAsync(2);
    }
Example #15
0
        public CatalogController(IHttpClientFactory clientFactory)
        {
            _httpClientFactory = clientFactory;

            _httpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(result => result.StatusCode == System.Net.HttpStatusCode.InternalServerError)
                               .Or <TimeoutRejectedException>()
                               .RetryAsync(3);

            _httpWaitAndRetryPolicy = Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                                      .WaitAndRetryAsync(3, sleepDurationProvider: retryCount =>
                                                         TimeSpan.FromSeconds(Math.Pow(2, retryCount) / 2),
                                                         onRetry: (httpResponseMessage, time, context) =>
            {
                if (httpResponseMessage.Result.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    Debug.WriteLine("There was issue with authentication");
                }
                else
                {
                    if (context.Contains("Logging") && context["Logging"].ToString() == "Enabled")
                    {
                        Debug.WriteLine(httpResponseMessage.Result.Content.ReadAsStringAsync().Result);
                    }
                }
            });

            _fallbackPolicy = Policy.HandleResult <HttpResponseMessage>(result => !result.IsSuccessStatusCode)
                              .FallbackAsync(new HttpResponseMessage(System.Net.HttpStatusCode.OK)
            {
                Content = new StringContent("Cached Default Result")
            });

            _timeoutPolicy = Policy.TimeoutAsync(seconds: 1);

            _policyWrap = _fallbackPolicy.WrapAsync(_httpWaitAndRetryPolicy.WrapAsync(_timeoutPolicy));
        }
        /// <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 override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <Progress> progress)
        {
            if (cancellationToken == null)
            {
                throw new ArgumentNullException(nameof(cancellationToken));
            }
            if (progress == null)
            {
                throw new ArgumentNullException(nameof(progress));
            }

            // Llama el servicio web de la API para hacer peticiones repetitivas al servidor.
            // El servicio esta programado para fallar despues de 3 peticiones en 5 segundos.

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

            progress.Report(ProgressWithMessage(typeof(Wrap_Fallback_WaitAndRetry_CircuitBreaker_Async).Name));
            progress.Report(ProgressWithMessage("======"));
            progress.Report(ProgressWithMessage(string.Empty));

            Stopwatch watch = null;

            // Definimos nuestro waitAndRetry policy: sigue intentando con intervalos de 200ms.
            var waitAndRetryPolicy = Policy
                                     .Handle <Exception>(e => !(e is BrokenCircuitException)) // Filtrado de excepción! No reintentamos si el circuit-breaker determina que el sistema invocado está fuera de servicio!
                                     .WaitAndRetryForeverAsync(
                attempt => TimeSpan.FromMilliseconds(200),
                (exception, calculatedWaitDuration) =>
            {
                progress.Report(ProgressWithMessage(".Log,vuelva e intentar: " + exception.Message, Color.Yellow));
                retries++;
            });

            // Definimos nuestro CircuitBreaker policy: cortar si la acción falla 4 veces seguidas.
            var circuitBreakerPolicy = Policy
                                       .Handle <Exception>()
                                       .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 4,
                durationOfBreak: TimeSpan.FromSeconds(3),
                onBreak: (ex, breakDelay) =>
            {
                progress.Report(ProgressWithMessage(".Breaker logging: Cortando el circuito por " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta));
                progress.Report(ProgressWithMessage("..debido a: " + ex.Message, Color.Magenta));
            },
                onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Llamado ok! Se cierra el circuito nuevamente!", Color.Magenta)),
                onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: el proximo llamado es de prueba!", Color.Magenta))
                );

            // Definimos un fallback policy: provee un buen mensaje de reemplazo para el usuario, si encontramos que el circuito estaba cortado.
            AsyncFallbackPolicy <string> fallbackForCircuitBreaker = Policy <string>
                                                                     .Handle <BrokenCircuitException>()
                                                                     .FallbackAsync(
                fallbackValue: "Por favor intente mas tarde [mensaje substituido por fallback policy]",
                onFallbackAsync: async b =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback capto llamada fallida por: " + b.Exception.Message
                                                    + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresDueToCircuitBreaking++;
            }
                );

            // Definimos un fallback policy: provee un buen mensaje substituto para el usuario, para cualquier excepcion.
            AsyncFallbackPolicy <string> fallbackForAnyException = Policy <string>
                                                                   .Handle <Exception>()
                                                                   .FallbackAsync(
                fallbackAction: async ct =>
            {
                await Task.FromResult(true);
                /* logica extra que se desee aquí */
                return("Por favor intente mas tarde [Fallback para cualquier excepción]");
            },
                onFallbackAsync: async e =>
            {
                await Task.FromResult(true);
                watch.Stop();
                progress.Report(ProgressWithMessage("Fallback captura eventualmented fallido por: " + e.Exception.Message
                                                    + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Red));
                eventualFailuresForOtherReasons++;
            }
                );

            // Combinamos el waitAndRetryPolicy y circuitBreakerPolicy en un PolicyWrap
            AsyncPolicyWrap myResilienceStrategy = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy);

            // Envuelve los dos fallback policies en el frente del wrap existente. Demuestra el hecho de que el PolicyWrap myResilienceStrategy de arriba es solo otro Policy, el cual puede ser envuelto también.
            // Con este patron, se puede construir una estrategia general programaticamente, reusando algunas partes en común (ej. Policy Wrap myResilienceStrategy) pero variendo otras partes (ej. Fallback) individualmente para diferentes llamados.
            AsyncPolicyWrap <string> policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy));

            // Para info: equivalente a: AsyncPolicyWrap<string> policyWrap = Policy.WrapAsync(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy);

            totalRequests = 0;

            using (var client = new HttpClient())
            {
                bool internalCancel = false;
                // Hacer lo siguiente hasta que una tecla sea presionada
                while (!internalCancel && !cancellationToken.IsCancellationRequested)
                {
                    totalRequests++;
                    watch = new Stopwatch();
                    watch.Start();

                    try
                    {
                        // Maneja el llamado acorde al policy wrap
                        string response = await policyWrap.ExecuteAsync(ct =>
                                                                        client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken);

                        watch.Stop();

                        // Muestra la respuesta en la consola
                        progress.Report(ProgressWithMessage("Respuesta : " + response + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Green));

                        eventualSuccesses++;
                    }
                    catch (Exception e) // try-catch innecesario ahora que tenemos un Fallback.Handle<Exception>. Sólo está aquí para demostrar que nunca llega hasta este codigo.
                    {
                        throw new InvalidOperationException("Nunca debería llegar hasta aquí.  Uso de fallbackForAnyException debería proveer un buen mensaje devuelta al usuario para cualquier excepción.", e);
                    }

                    // Espera medio segundo
                    await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);

                    internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable;
                }
            }
        }
Example #18
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.
            AsyncFallbackPolicy <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.
            AsyncFallbackPolicy <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.
            AsyncPolicyWrap 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.
            AsyncPolicyWrap <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>
        /// Generates the circuit breaker policy for a service.
        /// </summary>
        /// <param name="serviceInfo">The service to generate the circuit breaker policy for</param>
        /// <returns>The circuit policy</returns>
        protected AsyncPolicyWrap <ServiceResponse> GetCircuitBreakerPolicy(CalledServiceInfo serviceInfo)
        {
            return(CircuitBreakerPolicies.GetOrAdd(serviceInfo.CacheKey, _ =>
            {
                AsyncTimeoutPolicy timeoutPolicy = Policy
                                                   .TimeoutAsync(
                    serviceInfo.Timeout,
                    TimeoutStrategy.Pessimistic
                    );

                AsyncCircuitBreakerPolicy <ServiceResponse> circuitBreakerPolicy = Policy <ServiceResponse>
                                                                                   .Handle <TimeoutRejectedException>()
                                                                                   .OrResult(resultPredicate: serviceResponse => serviceResponse.Status == ServiceResponseStatus.Error)
                                                                                   .CircuitBreakerAsync(
                    handledEventsAllowedBeforeBreaking: serviceInfo.CircuitBreakerInfo.ExceptionCount,
                    durationOfBreak: serviceInfo.CircuitBreakerInfo.BreakDuration,
                    onBreak: (__, ___) =>
                {
                    Log.Warning("Service ({ServiceName}) has reached its threshold for the circuit breaker and the circuit has been opened", serviceInfo.Name);
                },
                    onReset: () =>
                {
                    Log.Warning("Service ({ServiceName}) has been determined to be back up, circuit closed again", serviceInfo.Name);
                }
                    );

                AsyncPolicyWrap <ServiceResponse> circuitBreakerWrappingTimeout = circuitBreakerPolicy
                                                                                  .WrapAsync(timeoutPolicy);

                AsyncFallbackPolicy <ServiceResponse> timeoutFallbackPolicy = Policy <ServiceResponse>
                                                                              .Handle <TimeoutRejectedException>()
                                                                              .FallbackAsync(
                    cancellationToken =>
                {
                    return Task.FromResult(new ServiceResponse
                    {
                        Status = ServiceResponseStatus.Timeout,
                        ServiceId = serviceInfo.Id
                    });
                });
                AsyncPolicyWrap <ServiceResponse> timeoutFallbackPolicyWrappingCircuitBreaker = timeoutFallbackPolicy
                                                                                                .WrapAsync(circuitBreakerWrappingTimeout);

                AsyncFallbackPolicy <ServiceResponse> exceptionFallbackPolicy = Policy <ServiceResponse>
                                                                                .Handle <Exception>()
                                                                                .FallbackAsync(
                    cancellationToken =>
                {
                    return Task.FromResult(new ServiceResponse
                    {
                        Status = ServiceResponseStatus.Error,
                        ServiceId = serviceInfo.Id
                    });
                });
                AsyncPolicyWrap <ServiceResponse> exceptionFallbackPolicyWrappingTimeoutFallback = exceptionFallbackPolicy
                                                                                                   .WrapAsync(timeoutFallbackPolicyWrappingCircuitBreaker);

                AsyncPolicyWrap <ServiceResponse> policy = exceptionFallbackPolicyWrappingTimeoutFallback;

                return policy;
            }));
        }
        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.
            AsyncFallbackPolicy <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.
            AsyncFallbackPolicy <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.
            AsyncPolicyWrap <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;
                }
            }
        }