Ejemplo n.º 1
0
 /// <summary>
 /// 超时
 /// </summary>
 /// <param name="wrappolicy"></param>
 /// <returns></returns>
 private AsyncPolicy SetTimeout(AsyncPolicy wrappolicy)
 {
     //超时异常,采用Pessimistic悲观策略
     if (TimeOutMilliseconds > 0 && wrappolicy != null)
     {
         wrappolicy = wrappolicy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic));
     }
     return(wrappolicy);
 }
        private AsyncPolicy BuildPolicy(AspectContext context, AsyncPolicy policy)
        {
            if (policy != null)
            {
                return(policy);
            }

            policy = Policy.NoOpAsync();
            if (IsEnableCircuitBreaker)
            {
                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)));
            }

            var policyFallBack = Policy
                                 .Handle <Exception>()
                                 .FallbackAsync((ctx, t) =>
            {
                var aspectContext         = (AspectContext)ctx["aspectContext"];
                var fallBackMethod        = context.ServiceMethod?.DeclaringType?.GetMethod(FallBackMethod);
                var fallBackResult        = fallBackMethod?.Invoke(context.Implementation, context.Parameters);
                aspectContext.ReturnValue = fallBackResult;

                return(Task.FromResult(fallBackResult));
            }, async(ex, t) => throw ex);

            policy = policyFallBack.WrapAsync(policy);
            policies.TryAdd(context.ServiceMethod, policy);

            return(policy);
        }
Ejemplo n.º 3
0
        public void Generic_wraps_generic_using_instance_wrap_syntax_should_set_outer_inner()
        {
            AsyncPolicy <int> policyA = Policy.NoOpAsync <int>();
            AsyncPolicy <int> policyB = Policy.NoOpAsync <int>();

            AsyncPolicyWrap <int> wrap = policyA.WrapAsync(policyB);

            wrap.Outer.Should().BeSameAs(policyA);
            wrap.Inner.Should().BeSameAs(policyB);
        }
Ejemplo n.º 4
0
        public AsyncPolicy <HttpResponseMessage> Build()
        {
            if (!this.policies.Any())
            {
                return(null);
            }

            AsyncPolicy <HttpResponseMessage> policy = this.policies[0];

            for (int i = 1; i < this.policies.Count; i++)
            {
                policy = policy.WrapAsync(this.policies[i]);
            }

            return(policy);
        }
Ejemplo n.º 5
0
 /// <summary>
 /// 熔断
 /// </summary>
 /// <param name="wrappolicy"></param>
 /// <returns></returns>
 private AsyncPolicy SetCircuitBreaker(AsyncPolicy wrappolicy)
 {
     if (IsEnableCircuitBreaker == E_Hystrix.Enable)
     {
         //异常ExceptionsAllowedBeforeBreaking次后进行熔断,熔断MillisecondsOfBreak后恢复
         var _wrappolicy = Policy.Handle <Exception>().CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak));
         if (wrappolicy == null)
         {
             wrappolicy = _wrappolicy;
         }
         else
         {
             wrappolicy = wrappolicy.WrapAsync(_wrappolicy);
         }
     }
     return(wrappolicy);
 }
Ejemplo n.º 6
0
 /// <summary>
 /// 重试
 /// </summary>
 /// <param name="wrappolicy"></param>
 /// <returns></returns>
 private AsyncPolicy SetRetry(AsyncPolicy wrappolicy)
 {
     if (MaxRetryTimes > 0)
     {
         //重试策略,RetryIntervalMilliseconds标识间隔多久重试一次
         var _wrappolicy = Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds));
         if (wrappolicy == null)
         {
             wrappolicy = _wrappolicy;
         }
         else
         {
             wrappolicy = wrappolicy.WrapAsync(_wrappolicy);
         }
     }
     return(wrappolicy);
 }
        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="onBreak">The on break.</param>
        /// <param name="onReset">The on reset.</param>
        /// <param name="onHalfOpen">The on half open.</param>
        /// <param name="onRetry">The on retry.</param>
        public ResiliencePolicies(
            Action <Exception, CircuitState, TimeSpan, Context>?onBreak = null,
            Action <Context>?onReset = null,
            Action?onHalfOpen        = null,
            Func <Exception, TimeSpan, int, Context, Task>?onRetry = null
            )
        {
            var onBreak_    = (onBreak ?? ((ex, state, duration, ctx) => { }));
            var onReset_    = onReset ?? ((Action <Context>)((ctx) => { }));
            var onHalfOpen_ = onHalfOpen ?? (() => { });
            var onRetry_    = onRetry ?? ((ex, duration, retryCount, ctx) => Task.CompletedTask);

            //_onBreak = onBreak_;
            //_onReset = onReset_;
            //_onHalfOpen = onHalfOpen_;
            //_onRetry = onRetry_;

            //BatchReading = DefaultReadingPolicy;

            AsyncPolicy retryReading = Policy.Handle <Exception>()
                                       .RetryForeverAsync((ex, i, c) => onRetry_(ex, TimeSpan.Zero, i, c));


            AsyncPolicy breaker = Policy.Handle <Exception>()
                                                            //.CircuitBreakerAsync(
                                                            //                10,
                                                            //                TimeSpan.FromSeconds(20),
                                                            //                onBreak_,
                                                            //                onReset_,
                                                            //                onHalfOpen_);
                                  .AdvancedCircuitBreakerAsync(
                failureThreshold: 0.5,                      // Break on >=50% actions result in handled exceptions...
                samplingDuration: TimeSpan.FromSeconds(20), // ... over any 10 second period
                minimumThroughput: 8,                       // ... provided at least 8 actions in the 10 second period.
                durationOfBreak: TimeSpan.FromSeconds(30),  // Break for 30 seconds.
                onBreak_,
                onReset_,
                onHalfOpen_);

            BatchReading = retryReading.WrapAsync(breaker);
        }
        private async Task <HttpResponseMessage> ExecuteWithRetryAndCircuitBreakerAsync(string uri, string authToken, Func <Task <HttpResponseMessage> > func)
        {
            var res = await _retryPolicy.WrapAsync(_circuitBreakerPolicy).ExecuteAsync(func);

            return(res);
        }
Ejemplo n.º 9
0
        private AsyncPolicy <object> GetPolicy(string route, Type returnValueType)
        {
            return(Policies.GetOrAdd(route, (key) =>
            {
                var service = ServiceFactory.Get(route);
                var serviceCircuitBreakerOptions = service.ServiceCircuitBreakerOptions;
                var circuitBreakerEvent = ServiceProvider.GetService <ICircuitBreakerEvent>();
                AsyncPolicy <object> policy = Policy <object> .Handle <Exception>().FallbackAsync(
                    async ct =>
                {
                    if (circuitBreakerEvent != null)
                    {
                        await circuitBreakerEvent.OnFallback(route, service.MethodInfo);
                    }
                    if (returnValueType == null)
                    {
                        return null;
                    }
                    if (service.ServiceCircuitBreakerOptions.HasInjection)
                    {
                        return await ScriptInjection.Run(route);
                    }
                    return returnValueType.IsValueType ? Activator.CreateInstance(returnValueType) : null;
                });
                if (serviceCircuitBreakerOptions.ExceptionsAllowedBeforeBreaking > 0)
                {
                    policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(serviceCircuitBreakerOptions.ExceptionsAllowedBeforeBreaking, serviceCircuitBreakerOptions.DurationOfBreak,
                                                                                              async(ex, state, ts, ctx) =>
                    {
                        if (circuitBreakerEvent != null)
                        {
                            await circuitBreakerEvent.OnBreak(route, service.MethodInfo, ex, ts);
                        }
                    },
                                                                                              async ctx =>
                    {
                        if (circuitBreakerEvent != null)
                        {
                            await circuitBreakerEvent.OnRest(route, service.MethodInfo);
                        }
                    },
                                                                                              async() =>
                    {
                        if (circuitBreakerEvent != null)
                        {
                            await circuitBreakerEvent.OnHalfOpen(route, service.MethodInfo);
                        }
                    }));
                }
                if (serviceCircuitBreakerOptions.Retry > 0)
                {
                    policy = policy.WrapAsync(Policy.Handle <Exception>().RetryAsync(serviceCircuitBreakerOptions.Retry,
                                                                                     async(ex, times) =>
                    {
                        if (circuitBreakerEvent != null)
                        {
                            await circuitBreakerEvent.OnRetry(route, service.MethodInfo, ex, times);
                        }
                    }));
                }

                if (serviceCircuitBreakerOptions.Timeout.Ticks > 0)
                {
                    policy = policy.WrapAsync(Policy.TimeoutAsync(serviceCircuitBreakerOptions.Timeout, TimeoutStrategy.Pessimistic,
                                                                  async(ctx, ts, task, ex) =>
                    {
                        if (circuitBreakerEvent != null)
                        {
                            await circuitBreakerEvent.OnTimeOut(route, service.MethodInfo, ex);
                        }
                    }));
                }
                return policy;
            }));
        }
Ejemplo n.º 10
0
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            //一个HystrixCommand中保持一个policy对象即可
            //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象
            //根据反射原理,同一个方法的MethodInfo是同一个对象,但是对象上取出来的HystrixCommandAttribute
            //每次获取的都是不同的对象,因此以MethodInfo为Key保存到policies中,确保一个方法对应一个policy实例
            policies.TryGetValue(context.ServiceMethod, out AsyncPolicy policy);
            lock (policies)            //因为Invoke可能是并发调用,因此要确保policies赋值的线程安全
            {
                if (policy == null)
                {
                    policy = Policy.NoOpAsync();                    //创建一个空的Policy
                    if (IsEnableCircuitBreaker)
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak)));
                    }
                    if (TimeOutMilliseconds > 0)
                    {
                        policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), TimeoutStrategy.Pessimistic));
                    }
                    if (MaxRetryTimes > 0)
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds)));
                    }

                    AsyncPolicy policyFallBack = Policy
                                                 .Handle <Exception>()
                                                 .FallbackAsync(async(ctx, t) =>
                    {
                        AspectContext aspectContext = (AspectContext)ctx["aspectContext"];
                        var fallBackMethod          = context.ServiceMethod.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) => {
                        //t.Add("error", ex.Message);
                    });

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

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

            pollyCtx["aspectContext"] = context;

            //Install-Package Microsoft.Extensions.Caching.Memory
            if (CacheTTLMilliseconds > 0)
            {
                //用类名+方法名+参数的下划线连接起来作为缓存key
                string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType
                                  + "." + context.ServiceMethod + string.Join("_", context.Parameters);
                //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值
                if (memoryCache.TryGetValue(cacheKey, out var cacheValue))
                {
                    context.ReturnValue = cacheValue;
                }
                else
                {
                    //如果缓存中没有,则执行实际被拦截的方法
                    await policy.ExecuteAsync(ctx => next(context), pollyCtx);

                    //存入缓存中
                    using (var cacheEntry = memoryCache.CreateEntry(cacheKey))
                    {
                        cacheEntry.Value = context.ReturnValue;
                        cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds);
                    }
                }
            }
            else            //如果没有启用缓存,就直接执行业务方法
            {
                await policy.ExecuteAsync(ctx => next(context), pollyCtx);
            }
        }