public void BulkHeadRejectsExecutionWhenQueueFull()
        {
            _processed.Clear();
            _rejected.Clear();
            bool exceptionThrown = false;
            var  bulkHead        = Policy.Bulkhead(1, 5, context =>
            {
                var id = context["id"];
                Console.Out.WriteLine($"Rejected id {id}");
                _rejected.Add((int)id);
            }); // max concurrency of 2, max queue size of 5

            Parallel.ForEach(_testData, id =>
            {
                try
                {
                    var context = new Polly.Context {
                        ["id"] = id
                    };
                    bulkHead.Execute((ctx) => SlowFunction(id), context);
                }
                catch (BulkheadRejectedException)
                {
                    // keep demo running
                    exceptionThrown = true;
                }
            });

            Assert.IsTrue(exceptionThrown);
            Assert.IsTrue(_processed.Count > 0);
            Assert.IsTrue(_rejected.Count > 0);
            Assert.IsTrue(_rejected.Count > _processed.Count); // we will always reject more since method takes 1 second
        }
Example #2
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  operationKey           = "SomeKey";
            Context contextPassedToExecute = new Context(operationKey);

            Context          contextPassedToOnRejected = null;
            Action <Context> onRejected = ctx => { contextPassedToOnRejected = ctx; };

            using (BulkheadPolicy <int> bulkhead = Policy.Bulkhead <int>(1, onRejected))
            {
                TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();
                using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
                {
                    Task.Run(() => {
                        bulkhead.Execute(() =>
                        {
                            tcs.Task.Wait();
                            return(0);
                        });
                    });

                    Within(CohesionTimeLimit, () => Expect(0, () => bulkhead.BulkheadAvailableCount, nameof(bulkhead.BulkheadAvailableCount)));

                    bulkhead.Invoking(b => b.Execute(_ => 1, contextPassedToExecute)).Should().Throw <BulkheadRejectedException>();

                    cancellationSource.Cancel();
                    tcs.SetCanceled();
                }

                contextPassedToOnRejected.Should().NotBeNull();
                contextPassedToOnRejected.OperationKey.Should().Be(operationKey);
                contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
            }
        }
Example #3
0
 public PrintPollyBulkhead()
 {
     bulkheadPolicy = Policy.Bulkhead(2, 2, onBulkheadRejected: (context) =>
     {
         Console.WriteLine(context.Count);
     });
 }
Example #4
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  executionKey           = Guid.NewGuid().ToString();
            Context contextPassedToExecute = new Context(executionKey);

            Context          contextPassedToOnRejected = null;
            Action <Context> onRejected = ctx => { contextPassedToOnRejected = ctx; };

            BulkheadPolicy <int> bulkhead = Policy.Bulkhead <int>(1, onRejected);

            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();

            using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
            {
                Task.Run(() => {
                    bulkhead.Execute(() =>
                    {
                        tcs.Task.Wait();
                        return(0);
                    });
                });

                Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(0)); // Time for the other thread to kick up and take the bulkhead.

                bulkhead.Invoking(b => b.Execute(() => 1, contextPassedToExecute)).ShouldThrow <BulkheadRejectedException>();

                cancellationSource.Cancel();
                tcs.SetCanceled();
            }

            contextPassedToOnRejected.Should().NotBeNull();
            contextPassedToOnRejected.ExecutionKey.Should().Be(executionKey);
            contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
        }
Example #5
0
        private static void _04_隔離()
        {
            var bulkheadPolicy = Policy.Bulkhead(1, 1, context =>
            {
                var msg = $"Reject:{context.PolicyKey}";
                Console.WriteLine(msg);
            });

            Console.WriteLine("請求網路資源中...");

            Task.Factory
            .StartNew(() =>
            {
                bulkheadPolicy.Execute(() =>
                {
                    Console.WriteLine("1.Execute Task,休息一下");
                    Thread.Sleep(TimeSpan.FromSeconds(5));
                });
            });

            Task.Factory
            .StartNew(() => { bulkheadPolicy.Execute(() => { Console.WriteLine("2.Execute Task"); }); });

            Task.Factory
            .StartNew(() => { bulkheadPolicy.Execute(() => { Console.WriteLine("3.Execute Task"); }); });

            Console.WriteLine("隔離,完成");
        }
 /// <summary>
 /// 构造函数
 /// </summary>
 /// <param name="maxParallelization">此Policy可以最多并行执行的action 大于0</param>
 /// <param name="maxQueuingActions">The maxmimum number of actions that may be queuing, waiting for an execution slot. 大于等于0</param>
 /// <param name="onBulkheadRejected">当过多的action超出限制时执行的回调操作</param>
 public BulkheadEx(int maxParallelization, int maxQueuingActions, Action <Context> onBulkheadRejected = null)
 {
     _bulkhead = Policy.Bulkhead(maxParallelization, maxQueuingActions, context =>
     {
         onBulkheadRejected?.Invoke(context);
     });
 }
Example #7
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  operationKey           = "SomeKey";
            Context contextPassedToExecute = new Context(operationKey);

            Context          contextPassedToOnRejected = null;
            Action <Context> onRejected = ctx => { contextPassedToOnRejected = ctx; };

            using (BulkheadPolicy bulkhead = Policy.Bulkhead(1, onRejected))
            {
                TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();

                Task.Run(() => { bulkhead.Execute(() => { tcs.Task.Wait(); }); });

                // Time for the other thread to kick up and take the bulkhead.
                Within(CohesionTimeLimit, () => Expect(0, () => bulkhead.BulkheadAvailableCount, nameof(bulkhead.BulkheadAvailableCount)));

                bulkhead.Invoking(b => b.Execute(ctx => { }, contextPassedToExecute)).Should()
                .Throw <BulkheadRejectedException>();

                tcs.SetCanceled();

                contextPassedToOnRejected.Should().NotBeNull();
                contextPassedToOnRejected.OperationKey.Should().Be(operationKey);
                contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
            }
        }
Example #8
0
        public override AsyncUnaryCall <TResponse> AsyncUnaryCall <TRequest, TResponse>(TRequest request,
                                                                                        ClientInterceptorContext <TRequest, TResponse> context,
                                                                                        AsyncUnaryCallContinuation <TRequest, TResponse> continuation)
        {
            var pollyRetry = Policy <AsyncUnaryCall <TResponse> > .Handle <Exception>()
                             .Retry(RetryCount);

            var pollyBulk = Policy.Bulkhead <AsyncUnaryCall <TResponse> >(MaxBulkhead);

            var pollyFallback = Policy <AsyncUnaryCall <TResponse> > .Handle <Exception>()
                                .Fallback(item =>
            {
                return(!string.IsNullOrEmpty(FallbackMethod)
                        ? UseNewMethod <TResponse>(new object[] { request })
                        : null);
            });

            var timeoutPolly = Policy.Timeout <AsyncUnaryCall <TResponse> >(30);

            var policy = Policy.Wrap(pollyFallback, pollyRetry, timeoutPolly, pollyBulk);

            var response = policy.Execute(() =>
            {
                var responseCon = continuation(request, context);
                var call        = new AsyncUnaryCall <TResponse>(responseCon.ResponseAsync,
                                                                 responseCon.ResponseHeadersAsync,
                                                                 responseCon.GetStatus,
                                                                 responseCon.GetTrailers,
                                                                 responseCon.Dispose);

                return(call);
            });

            return(response);
        }
Example #9
0
        public void Bulkhead_Queing_and_Parallel_Execution()
        {
            var maximumNumberOfActionsInParallel     = 0;
            var minumumNumberOfSlotsAvailableInQueue = 10;
            var parallelActionCount = 0;
            var policy = Policy.Bulkhead(4, 8);

            Parallel.ForEach(Enumerable.Range(0, 9), p =>
            {
                policy.Execute(() =>
                {
                    parallelActionCount++;
                    if (policy.QueueAvailableCount < minumumNumberOfSlotsAvailableInQueue)
                    {
                        minumumNumberOfSlotsAvailableInQueue = policy.QueueAvailableCount;
                    }
                    if (parallelActionCount > maximumNumberOfActionsInParallel)
                    {
                        maximumNumberOfActionsInParallel = parallelActionCount;
                    }
                    Thread.Sleep(100);
                    parallelActionCount--;
                }
                               );
            });
            Assert.That(FILL.__IN,
                        Is_.Equal_To(maximumNumberOfActionsInParallel + minumumNumberOfSlotsAvailableInQueue));
        }
Example #10
0
        public void Bulkhead_when_Queue_is_Full()
        {
            var exceptionCount = 0;
            var policy         = Policy.Bulkhead(4, 2);

            try
            {
                Parallel.ForEach(Enumerable.Range(0, 9), p =>
                {
                    policy.Execute(() =>
                    {
                        Thread.Sleep(100);
                    }
                                   );
                });
            }
            catch (AggregateException ae)
            {
                foreach (var ex in ae.InnerExceptions)
                {
                    if (ex is BulkheadRejectedException)
                    {
                        exceptionCount++;
                    }
                }
            }

            Assert.That(FILL._IN, Is_.Equal_To(exceptionCount));
        }
Example #11
0
        public void Should_throw_when_maxQueuingActions_less_than_zero()
        {
            Action policy = () => Policy
                            .Bulkhead <int>(1, -1);

            policy.ShouldThrow <ArgumentOutOfRangeException>().And
            .ParamName.Should().Be("maxQueuingActions");
        }
Example #12
0
        public void Should_throw_when_onBulkheadRejected_is_null()
        {
            Action policy = () => Policy
                            .Bulkhead <int>(1, 0, null);

            policy.ShouldThrow <ArgumentNullException>().And
            .ParamName.Should().Be("onBulkheadRejected");
        }
Example #13
0
        public void Should_throw_when_maxparallelization_less_or_equal_to_zero()
        {
            Action policy = () => Policy
                            .Bulkhead <int>(0, 1);

            policy.ShouldThrow <ArgumentOutOfRangeException>().And
            .ParamName.Should().Be("maxParallelization");
        }
Example #14
0
        public static Policy CreatePolly()
        {
            //超时
            var timeout = Policy.Timeout(5);//Handle<TimeoutRejectedException>();

            //var retry = Policy.Handle<Exception>().WaitAndRetry(5, (i,e) =>
            //{
            //    e
            //});

            //重试
            var retry = Policy.Handle <Exception>().Retry(5, (e, i) =>
            {
                Console.WriteLine(e);
            });

            //等待重试
            var wait = Policy.Handle <Exception>().WaitAndRetry(5,                                //重试次数
                                                                i => TimeSpan.FromSeconds(3 * i), //间隔3秒*次数
                                                                (ex, time) => { Console.WriteLine(ex); });

            //降级
            var fallback = Policy.Handle <Exception>().Fallback(() =>
            {
                Console.WriteLine("降级");
            }, ex =>
            {
                Console.WriteLine(ex.Message);
            });

            //5次错误熔断,10秒重试
            var _break = Policy.Handle <Exception>().CircuitBreaker(5, TimeSpan.FromSeconds(10),
                                                                    (e, t) =>//OPEN打开熔断
            {
                Console.WriteLine("开始熔断");
            }, () =>    //COLSE 关闭熔断
            {
                Console.WriteLine("关闭熔断");
            }, () =>    //HALF-OPEN 重试半开
            {
                Console.WriteLine("重试半开");
            });

            //高级熔断器
            var breaks = Policy.Handle <Exception>()
                         .AdvancedCircuitBreaker(
                0.5,                       //故障阈值50%
                TimeSpan.FromSeconds(10),  //故障采样时间
                6,                         //最小吞吐量【10秒最少执行6次】
                TimeSpan.FromSeconds(15)); //熔断时间

            //舱壁隔离【限流】 控制并发
            var bulk = Policy.Bulkhead(
                10,  //最大并发通过量
                20); //最大排队数量

            return(Policy.Wrap(fallback, _break, retry, timeout));
        }
Example #15
0
        public static string[] TestBulkhead(int maxParallel, int queued)
        {
            var policy = Policy.Bulkhead(maxParallel, queued, (context) =>
            {
                Debug.Write("Slooooooow doooooooown");
            });

            return(policy.Execute(() =>
            {
                return new string[] { "value1", "value2" };
            }));
        }
    public static void Main()
    {
        int    maxRetryCount = 6;
        double circuitBreakDurationSeconds = 0.2 /* experiment with effect of shorter or longer here, eg: change to = 1, and the fallbackForCircuitBreaker is correctly invoked */;
        int    maxExceptionsBeforeBreaking = 4;  /* experiment with effect of fewer here, eg change to = 1, and the fallbackForCircuitBreaker is correctly invoked */
        int    maxParallelizations         = 2;
        int    maxQueuingActions           = 2;
        var    retryPolicy = Policy.Handle <Exception>(e => (e is HttpRequestException || (/*!(e is BrokenCircuitException) &&*/ e.InnerException is HttpRequestException))) // experiment with introducing the extra (!(e is BrokenCircuitException) && ) clause here, if necessary/desired, depending on goal
                             .WaitAndRetry(
            retryCount: maxRetryCount,
            sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(50 * Math.Pow(2, attempt)),
            onRetry: (ex, calculatedWaitDuration, retryCount, context) =>
        {
            Console.WriteLine(String.Format("Retry => Count: {0}, Wait duration: {1}, Policy Wrap: {2}, Policy: {3}, Endpoint: {4}, Exception: {5}", retryCount, calculatedWaitDuration, context.PolicyWrapKey, context.PolicyKey, context.OperationKey, ex.Message));
        });
        var circuitBreaker = Policy.Handle <Exception>(e => (e is HttpRequestException || e.InnerException is HttpRequestException))
                             .CircuitBreaker(maxExceptionsBeforeBreaking,
                                             TimeSpan.FromSeconds(circuitBreakDurationSeconds),
                                             onBreak: (ex, breakDuration) => {
            Console.WriteLine(String.Format("Circuit breaking for {0} ms due to {1}", breakDuration.TotalMilliseconds, ex.Message));
        },
                                             onReset: () => {
            Console.WriteLine("Circuit closed again.");
        },
                                             onHalfOpen: () => { Console.WriteLine("Half open."); });
        var sharedBulkhead            = Policy.Bulkhead(maxParallelizations, maxQueuingActions);
        var fallbackForCircuitBreaker = Policy <bool>
                                        .Handle <BrokenCircuitException>()
                                        /* .OrInner<BrokenCircuitException>() */                               // Consider this if necessary.
                                        /* .Or<Exception>(e => circuitBreaker.State != CircuitState.Closed) */ // This check will also detect the circuit in anything but healthy state, regardless of the final exception thrown.
                                        .Fallback(
            fallbackValue: false,
            onFallback: (b, context) =>
        {
            Console.WriteLine(String.Format("Operation attempted on broken circuit => Policy Wrap: {0}, Policy: {1}, Endpoint: {2}", context.PolicyWrapKey, context.PolicyKey, context.OperationKey));
        }
            );

        var fallbackForAnyException = Policy <bool>
                                      .Handle <Exception>()
                                      .Fallback <bool>(
            fallbackAction: (context) => { return(false); },
            onFallback: (e, context) =>
        {
            Console.WriteLine(String.Format("An unexpected error occured => Policy Wrap: {0}, Policy: {1}, Endpoint: {2}, Exception: {3}", context.PolicyWrapKey, context.PolicyKey, context.OperationKey, e.Exception.Message));
        }
            );

        var  resilienceStrategy = Policy.Wrap(retryPolicy, circuitBreaker, sharedBulkhead);
        var  policyWrap         = fallbackForAnyException.Wrap(fallbackForCircuitBreaker.Wrap(resilienceStrategy));
        bool outcome            = policyWrap.Execute((context) => CallApi("http://www.doesnotexistattimeofwriting.com/"), new Context("some endpoint info"));
    }
Example #17
0
        //Polly 可以实现重试、断路、超时、隔离、回退和缓存策略
        public static void TestSomething()
        {
            //断路(Circuit-breaker)
            //这句代码设定的策略是,当系统出现两次某个异常时,就停下来,等待 1 分钟后再继续。这是基本的用法,你还可以在断路时定义中断的回调和重启的回调。
            Policy.Handle <SomeException>().CircuitBreaker(2, TimeSpan.FromMinutes(1));

            //超时(Timeout)
            //当系统超过一定时间的等待,我们就几乎可以判断不可能会有成功的结果。比如平时一个网络请求瞬间就完成了,如果有一次网络请求超过了 30 秒还没完成,我们就知道这次大概率是不会返回成功的结果了。因此,我们需要设置系统的超时时间,避免系统长时间做无谓的等待。
            //这里设置了超时时间不能超过 30 秒,否则就认为是错误的结果,并执行回调。
            Policy.Timeout(30, onTimeout: (context, timespan, task) =>
            {
                // do something
            });


            //隔离(Bulkhead Isolation)
            //当系统的一处出现故障时,可能促发多个失败的调用,很容易耗尽主机的资源(如 CPU)。
            //下游系统出现故障可能导致上游的故障的调用,甚至可能蔓延到导致系统崩溃。所以要将可控的操作限制在一个固定大小的资源池中,以隔离有潜在可能相互影响的操作。
            //下面是隔离策略的一个基本用法:
            //这个策略是最多允许 12 个线程并发执行,如果执行被拒绝,则执行回调。
            Policy.Bulkhead(12, context =>
            {
                // do something
            });

            //回退(Fallback)
            //有些错误无法避免,就要有备用的方案。这个就像浏览器不支持一些新的 CSS 特性就要额外引用一个 polyfill 一样。
            //一般情况,当无法避免的错误发生时,我们要有一个合理的返回来代替失败。
            //比如很常见的一个场景是,当用户没有上传头像时,我们就给他一个默认头像,这种策略可以这样定义:
            //Policy.Handle<SomeException>().Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar());
            Policy.Handle <SomeException>().Fallback(() => { Console.WriteLine("Fallback"); });

            //缓存(Cache)
            //一般我们会把频繁使用且不会怎么变化的资源缓存起来,以提高系统的响应速度。
            //如果不对缓存资源的调用进行封装,那么我们调用的时候就要先判断缓存中有没有这个资源,有的话就从缓存返回,否则就从资源存储的地方(比如数据库)获取后缓存起来,
            //再返回,而且有时还要考虑缓存过期和如何更新缓存的问题。Polly 提供了缓存策略的支持,使得问题变得简单。
            //这是官方的一个使用示例用法,它定义了缓存 5 分钟过期的策略,然后把这个策略应用在指定的 Key(即 FooKey)上。
            //这一块内容值得用一整篇的内容来讲,下次有机会再详细讲讲 Polly 的缓存策略。
            var memoryCacheProvider = new MemoryCacheProvider();
            var cachePolicy         = Policy.Cache(memoryCacheProvider, TimeSpan.FromMinutes(5));
            var result = cachePolicy.Execute(context => getFoo(), new Context("FooKey"));

            //策略包(Policy Wrap)
            //一种操作会有多种不同的故障,而不同的故障处理需要不同的策略。这些不同的策略必须包在一起,作为一个策略包,才能应用在同一种操作上。这就是文章开头说的 Polly 的弹性,即各种不同的策略能够灵活地组合起来。
            //策略包的基本用法是这样的:
            //先是把预先定义好的多种不同的策略包在一起,作为一个整体策略,然后应用在同一个操作上。
            //var policyWrap = Policy.Wrap(fallback, cache, retry, breaker, timeout, bulkhead);
            //policyWrap.Execute();
        }
Example #18
0
        public static void Run()
        {
            //声明最大并发执行线程数、线程队列数
            var policy = Policy.Bulkhead(5, 10);

            Parallel.For(0, 100, (i) =>
            {
                var result = policy.Execute <string>(() =>
                {
                    return(GetHtml("http://baidu.com"));
                });
                Console.WriteLine($"成功获取到数据:{result}");
            });
            Console.ReadKey();
        }
 public static void Bulkhead()
 {
     try
     {
         var policy = Policy.Bulkhead(5, 2, context => {
             Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "---" + context.CorrelationId);
         });
         var arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
         Parallel.ForEach(arr, (p) =>
         {
             try
             {
                 //开始执行
                 policy.Execute(() =>
                 {
                     Console.WriteLine($"{DateTime .Now}  元素:{p}  线程ID:{Thread.CurrentThread.ManagedThreadId}");
                 });
             }
             catch (Exception exc)
             {
                 Console.WriteLine("内部:" + exc.Message);
             }
         });
         //for (int i = 0; i < 10; i++)
         //{
         //    new Thread(() =>
         //    {
         //        try
         //        {
         //            //开始执行
         //            policy.Execute(() =>
         //            {
         //                Console.WriteLine("开始" + Thread.CurrentThread.ManagedThreadId + "---" + DateTime.Now);
         //            });
         //        }
         //        catch(Exception exc)
         //        {
         //            Console.WriteLine("内部:"+exc.Message);
         //        }
         //    }).Start();
         //}
     }
     catch (Exception exc)
     {
         Console.WriteLine($"{exc.GetType().FullName}   Excepiton:{exc.Message}");
     }
     Console.ReadLine();
 }
Example #20
0
        /// <inheritdoc />
        public override void Start()
        {
            ThrowIfDisposed();
            Guard.IsValid(() => Configuration.MaximumThreads, Configuration.MaximumThreads, i => i > 0,
                          "The Configuration.MaximumThreads must be greater than 0");

            if (_smartThreadPool != null)
            {
                throw new DotNetWorkQueueException("Start must only be called 1 time");
            }

            _smartThreadPool = Policy.Bulkhead(_configuration.MaximumThreads,
                                               _configuration.MaxQueueSize, OnBulkheadRejected);

            Configuration.SetReadOnly();
        }
        public void Run()
        {
            var policy = Policy.Bulkhead(2, context =>
            {
                Console.WriteLine("It's Bulkhead, throw BulkheadRejectedException.");
            });

            try
            {
                Console.WriteLine(DateTime.Now.ToString() + "-Run BulkheadDemo...");
                policy.Execute(Invoke);
            }
            catch (Exception ex)
            {
                Console.WriteLine(DateTime.Now.ToString() + "-Run BulkheadDemo" + ": Exception->" + ex.Message);
            }
        }
Example #22
0
        public DbRetryPolicy()
        {
            var jitterer = new Random();

            var retryPolicyWithJitterAsync = Policy.Handle <SqlException>(exception => _sqlExceptions.Contains(exception.Number)).
                                             WaitAndRetryAsync(
                retryCount: RETRY_ATTEMPTS_ON_TRANSIENT_ERROR,
                sleepDurationProvider: retryNumber => TimeSpan.FromSeconds(Math.Pow(2, retryNumber)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100))
                );

            var bulkheadPolicyAsync = Policy.BulkheadAsync(maxParallelization: 3, maxQueuingActions: 25);

            var circuitBreakerPolicyAsync = Policy
                                            .Handle <SqlException>(exception => _sqlExceptions.Contains(exception.Number)).
                                            AdvancedCircuitBreakerAsync(
                failureThreshold: 0.25,                                 // If 25% or more of requests fail
                samplingDuration: TimeSpan.FromSeconds(60),             // in a 60 second period
                minimumThroughput: 7,                                   // and there have been at least 7 requests in that time
                durationOfBreak: TimeSpan.FromSeconds(30)               // then open the circuit for 30 seconds
                );

            RetryPolicyAsync = Policy.WrapAsync(retryPolicyWithJitterAsync, bulkheadPolicyAsync, circuitBreakerPolicyAsync);


            var bulkheadPolicy = Policy.Bulkhead(maxParallelization: 3, maxQueuingActions: 25);

            var retryPolicyWithJitter = Policy.Handle <SqlException>(exception => _sqlExceptions.Contains(exception.Number)).
                                        WaitAndRetry(
                retryCount: RETRY_ATTEMPTS_ON_TRANSIENT_ERROR,
                sleepDurationProvider: retryNumber => TimeSpan.FromSeconds(Math.Pow(2, retryNumber)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100))
                );


            var circuitBreakerPolicy = Policy
                                       .Handle <SqlException>(exception => _sqlExceptions.Contains(exception.Number)).
                                       AdvancedCircuitBreaker(
                failureThreshold: 0.25,                             // If 25% or more of requests fail
                samplingDuration: TimeSpan.FromSeconds(60),         // in a 60 second period
                minimumThroughput: 7,                               // and there have been at least 7 requests in that time
                durationOfBreak: TimeSpan.FromSeconds(30)           // then open the circuit for 30 seconds
                );


            RetryPolicy = Policy.Wrap(retryPolicyWithJitter, bulkheadPolicy, circuitBreakerPolicy);
        }
        public static void Test()
        {
            var policy = Policy.Bulkhead(5, (context) =>
            {
                Console.WriteLine("请求量太大");
            });

            for (int i = 0; i < 1000; i++)
            {
                Task.Run(() =>
                {
                    policy.Execute(() =>
                    {
                        Thread.Sleep(TimeSpan.FromSeconds(1));
                        Console.WriteLine("方法执行完成");
                    });
                });
            }
            Console.WriteLine("over");
        }
Example #24
0
        private async Task <UserResponseModel> GetUserListAsync(PriorityType priorityType, int results, int page)
        {
            UserResponseModel userResponseList = null;

            var apiRequestelector = new ApiRequestSelector <IRandomUserEndpoint>(_userEnpoint, priorityType);

            //Policy.Timeout(20);
            Policy.Bulkhead(10, 10);
            userResponseList = await Policy
                               .Handle <ApiException>(exception => exception.StatusCode == HttpStatusCode.ServiceUnavailable)
                               //.CircuitBreakerAsync(2,TimeSpan.FromSeconds(5))
                               //.AdvancedCircuitBreaker(failureThreshold: 0.5,
                               //                        samplingDuration: TimeSpan.FromSeconds(10),
                               //                        minimumThroughput: 1,
                               //                        durationOfBreak: TimeSpan.FromSeconds(30))
                               //.FallbackAsync((t) => Task.FromResult(new UserResponseModel()))
                               .WaitAndRetryAsync(5, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
                               .ExecuteAsync(async() => await apiRequestelector.GetApiRequestByPriority()?.GetUserList(results, page));

            return(userResponseList);
        }
Example #25
0
        /// <summary>
        /// Adds a new work group.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="concurrencyLevel">The concurrency level.</param>
        /// <param name="maxQueueSize">Maximum size of the queue. Work groups have a queue that is separate per queue, and is not shared with non work group items</param>
        /// <returns></returns>
        /// <exception cref="DotNetWorkQueueException">Start must be called on the scheduler before adding work groups</exception>
        public override IWorkGroup AddWorkGroup(string name, int concurrencyLevel, int maxQueueSize)
        {
            ThrowIfDisposed();

            if (_smartThreadPool == null)
            {
                throw new DotNetWorkQueueException("Start must be called on the scheduler before adding work groups");
            }

            var group = new WorkGroup(name, concurrencyLevel, maxQueueSize);

            if (_groups.ContainsKey(group))
            {
                return(_groups[group].GroupInfo);
            }

            var groupWithItem = new WorkGroupWithItem(group, Policy.Bulkhead(concurrencyLevel, maxQueueSize, OnBulkheadRejected), _metrics.Counter(
                                                          $"work group {name}", Units.Items));

            _groups.TryAdd(group, groupWithItem);
            return(groupWithItem.GroupInfo);
        }
Example #26
0
        public void Should_control_executions_queuing_and_rejections_per_specification_with_cancellations(
            int maxParallelization, int maxQueuingActions, int totalActions, bool cancelQueuing,
            bool cancelExecuting, string scenario)
        {
            if (totalActions < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(totalActions));
            }
            scenario = String.Format("MaxParallelization {0}; MaxQueuing {1}; TotalActions {2}; CancelQueuing {3}; CancelExecuting {4}: {5}", maxParallelization, maxQueuingActions, totalActions, cancelQueuing, cancelExecuting, scenario);

            BulkheadPolicy <ResultPrimitive> bulkhead = Policy.Bulkhead <ResultPrimitive>(maxParallelization, maxQueuingActions);

            // Set up delegates which we can track whether they've started; and control when we allow them to complete (to release their semaphore slot).
            actions = new TraceableAction[totalActions];
            for (int i = 0; i < totalActions; i++)
            {
                actions[i] = new TraceableAction(i, statusChanged, testOutputHelper);
            }

            // Throw all the delegates at the bulkhead simultaneously.
            Task[] tasks = new Task[totalActions];
            for (int i = 0; i < totalActions; i++)
            {
                tasks[i] = actions[i].ExecuteOnBulkhead(bulkhead);
            }

            testOutputHelper.WriteLine("Immediately after queueing...");
            testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
            testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
            OutputActionStatuses();

            // Assert the expected distributions of executing, queuing, rejected and completed - when all delegates thrown at bulkhead.
            int expectedCompleted    = 0;
            int expectedCancelled    = 0;
            int expectedExecuting    = Math.Min(totalActions, maxParallelization);
            int expectedRejects      = Math.Max(0, totalActions - maxParallelization - maxQueuingActions);
            int expectedQueuing      = Math.Min(maxQueuingActions, Math.Max(0, totalActions - maxParallelization));
            int expectedBulkheadFree = maxParallelization - expectedExecuting;
            int expectedQueueFree    = maxQueuingActions - expectedQueuing;

            try
            {
                actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, scenario + ", when checking expectedExecuting"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, scenario + ", when checking expectedQueuing"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, scenario + ", when checking expectedRejects"));
                actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, scenario + ", when checking expectedCompleted");
                actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, scenario + ", when checking expectedCancelled");
                Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, scenario + ", when checking expectedBulkheadFree"));
                Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, scenario + ", when checking expectedQueueFree"));
            }
            finally
            {
                testOutputHelper.WriteLine("Expected initial state verified...");
                testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                OutputActionStatuses();
            }

            // Complete or cancel delegates one by one, and expect others to take their place (if a slot released and others remain queueing); until all work is done.
            while (expectedExecuting > 0)
            {
                if (cancelQueuing)
                {
                    testOutputHelper.WriteLine("Cancelling a queueing task...");

                    actions.First(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Cancel();

                    expectedCancelled++;
                    expectedQueuing--;
                    expectedQueueFree++;

                    cancelQueuing = false;
                }
                else if (cancelExecuting)
                {
                    testOutputHelper.WriteLine("Cancelling an executing task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).Cancel();

                    expectedCancelled++;
                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }

                    cancelExecuting = false;
                }
                else // Complete an executing delegate.
                {
                    testOutputHelper.WriteLine("Completing a task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).AllowCompletion();

                    expectedCompleted++;

                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }
                }
                try
                {
                    actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, scenario + ", when checking expectedExecuting"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, scenario + ", when checking expectedQueuing"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, scenario + ", when checking expectedCompleted"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, scenario + ", when checking expectedCancelled"));
                    actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, scenario + ", when checking expectedRejects");
                    Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, scenario + ", when checking expectedBulkheadFree"));
                    Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, scenario + ", when checking expectedQueueFree"));
                }
                finally
                {
                    testOutputHelper.WriteLine("End of next loop iteration...");
                    testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                    testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                    OutputActionStatuses();
                }
            }

            EnsureNoUnbservedTaskExceptions(tasks);
            testOutputHelper.WriteLine("Verifying all tasks completed...");
            Within(shimTimeSpan, () => tasks.All(t => t.IsCompleted).Should().BeTrue());

            #endregion
        }
Example #27
0
        /// <summary>
        /// Polly方法使用代码Demo
        /// </summary>
        /// <returns></returns>
        static async Task PollyCodeDemoAsync()
        {
            Policy.Handle <Exception>().WaitAndRetry(
                3,
                retryAttempt => TimeSpan.FromSeconds(5),
                // 处理异常、
                (exception, timespan, retryCount, context) =>
            {
                // doSomething
                Console.WriteLine($"{DateTime.Now} - 重试 {retryCount} 次 - 抛出{exception.GetType()}-{timespan.TotalMilliseconds}");
            })
            .Execute(() =>
            {
                GetServiceResult();
            });
            Policy.Handle <Exception>()
            .CircuitBreaker(
                // 熔断前允许出现几次错误
                3,
                // 熔断时间
                TimeSpan.FromSeconds(5),
                // 熔断时触发
                onBreak: (ex, breakDelay) =>
            {
                Console.WriteLine("断路器:开启状态(熔断时触发)");
            },
                // 熔断恢复时触发
                onReset: () =>
            {
                Console.WriteLine("断路器:关闭状态(熔断恢复时触发)");
            },
                // 熔断时间到了之后触发,尝试放行少量(1次)的请求,
                onHalfOpen: () =>
            {
                Console.WriteLine("断路器:半开启状态(熔断时间到了之后触发)");
            }
                );


            Policy.Handle <Exception>().CircuitBreaker(5, TimeSpan.FromSeconds(10))
            .Execute(() =>
            {
                // do something
            });

            // 单个异常类型
            Policy.Handle <Exception>();

            // 限定条件的单个异常
            Policy.Handle <ArgumentException>(ex => ex.ParamName == "ID");

            // 多个异常类型
            Policy.Handle <Exception>().Or <ArgumentException>();

            // 限定条件的多个异常
            Policy.Handle <Exception>(ex => ex.Message == "请求超时")
            .Or <ArgumentException>(ex => ex.ParamName == "ID");

            // Inner Exception 异常里面的异常类型
            Policy.HandleInner <Exception>()
            .OrInner <ArgumentException>(ex => ex.ParamName == "ID");

            // 返回结果加限定条件
            Policy.HandleResult <HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound);

            // 处理多个返回结果
            Policy.HandleResult <HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
            .OrResult(r => r.StatusCode == HttpStatusCode.BadGateway);

            // 处理元类型结果 (用.Equals)
            Policy.HandleResult(HttpStatusCode.InternalServerError)
            .OrResult(HttpStatusCode.BadGateway);

            // 重试1次
            Policy.Handle <Exception>().Retry();

            // 重试3次
            Policy.Handle <Exception>().Retry(3);

            // 重试3次,加上重试时的action参数
            Policy.Handle <Exception>().Retry(3, (exception, retryCount) =>
            {
                // do Something
            });

            // 不断重试,直到成功
            Policy.Handle <Exception>().RetryForever();

            // 不断重试,带action参数在每次重试的时候执行
            Policy.Handle <Exception>().RetryForever(exception =>
            {
                // do Something
            });

            // 重试3次,每次等待5s
            Policy.Handle <Exception>().WaitAndRetry(
                3,
                retryAttempt => TimeSpan.FromSeconds(5),
                // 处理异常、等待时间、重试第几次
                (exception, timespan, retryCount, context) =>
            {
                // do Something
            });

            // 重试3次,分别等待1、2、3秒。
            Policy.Handle <Exception>().WaitAndRetry(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(2),
                TimeSpan.FromSeconds(3)
            });

            Policy.Handle <Exception>().CircuitBreaker(2, TimeSpan.FromSeconds(10));
            Policy.Handle <Exception>().Fallback(() =>
            {
                // do something
            });

            // 设置超时时间为30s
            Policy.Timeout(30, onTimeout: (context, timespan, task, ex) =>
            {
                // do something
            });

            // 超时分为乐观超时与悲观超时,乐观超时依赖于CancellationToken ,它假设我们的具体执行的任务都支持CancellationToken。
            // 那么在进行timeout的时候,它会通知执行线程取消并终止执行线程,避免额外的开销。下面的乐观超时的具体用法 。
            HttpResponseMessage httpResponse = await Policy.TimeoutAsync(30)
                                               .ExecuteAsync(
                async ct => await new HttpClient().GetAsync(""),
                CancellationToken.None
                );

            // 悲观超时与乐观超时的区别在于,如果执行的代码不支持取消CancellationToken,
            // 它还会继续执行,这会是一个比较大的开销。
            Policy.Timeout(30, TimeoutStrategy.Pessimistic);



            Policy.Bulkhead(12);
            // 同时,我们还可以控制一个等待处理的队列长度
            Policy.Bulkhead(12, 2);

            // 以及当请求执行操作被拒绝的时候,执行回调
            Policy.Bulkhead(12, context =>
            {
                // do something
            });

            //var policyWrap = Policy.Wrap(fallback, breaker, timeout, retry, bulkhead);
            //policyWrap.Execute(() =>
            //{
            //    // do something
            //});
        }
Example #28
0
 protected override IBulkheadPolicy GetBulkhead(int maxParallelization, int maxQueuingActions)
 {
     return(Policy.Bulkhead <ResultPrimitive>(maxParallelization, maxQueuingActions));
 }
 public static BulkheadPolicy GenerateTotalNetworkRequestsNonAsyncPolicy(PolicySettings settings)
 {
     return(Policy.Bulkhead(settings.MaximumSimultaneousNetworkRequests));
 }
 private static Policy <ResultPrimitive> BulkheadPolicy()
 {
     return(Policy
            .Bulkhead <ResultPrimitive>(1));
 }