/// <summary>
        /// Puts the specified value in the cache.
        /// </summary>
        /// <param name="key">The cache key.</param>
        /// <param name="value">The value to put into the cache.</param>
        /// <param name="ttl">The time-to-live for the cache entry.</param>
        public void Put(string key, object value, Ttl ttl)
        {
#if PORTABLE
            using (Microsoft.Extensions.Caching.Memory.ICacheEntry entry = _cache.CreateEntry(key)) {
                entry.Value = value;
                if (ttl.SlidingExpiration)
                {
                    entry.SlidingExpiration = ttl.Timespan;
                }
                else
                {
                    entry.AbsoluteExpirationRelativeToNow = ttl.Timespan;
                }
            }
#else
            System.Runtime.Caching.CacheItemPolicy cacheItemPolicy = new System.Runtime.Caching.CacheItemPolicy();
            if (ttl.SlidingExpiration)
            {
                cacheItemPolicy.SlidingExpiration = ttl.Timespan;
            }
            else
            {
                cacheItemPolicy.AbsoluteExpiration = SystemClock.DateTimeOffsetUtcNow().Add(ttl.Timespan);
            }
            _cache.Set(key, value, cacheItemPolicy);
#endif
        }
Ejemplo n.º 2
0
        public void Get_should_return_instance_previously_stored_in_cache()
        {
#if PORTABLE
            MemoryCacheImplementation memoryCache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());
#else
            MemoryCacheImplementation memoryCache = System.Runtime.Caching.MemoryCache.Default;
#endif

            string key   = "anything";
            object value = new object();
#if PORTABLE
            using (Microsoft.Extensions.Caching.Memory.ICacheEntry entry = memoryCache.CreateEntry(key)) {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
                entry.Value = value;
            }
#else
            memoryCache[key] = value;
#endif

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);
            object got = provider.Get(key);
            got.Should().BeSameAs(value);
        }
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            //一个HystrixCommand中保持一个policy对象即可
            //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象
            //根据反射原理,同一个方法的MethodInfo是同一个对象,但是对象上取出来的HystrixCommandAttribute
            //每次获取的都是不同的对象,因此以MethodInfo为Key保存到policies中,确保一个方法对应一个policy实例
            policies.TryGetValue(context.ServiceMethod, out Policy policy);
            lock (policies)//因为Invoke可能是并发调用,因此要确保policies赋值的线程安全
            {
                if (policy == null)
                {
                    policy = Policy.NoOpAsync();//创建一个空的Policy
                    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)));
                    }
                    Policy 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) => { });

                    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);
            }
        }
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            //一个HystrixCommand中保持一个policy对象即可
            //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象
            //根据反射原理,同一个方法就对应一个HystrixCommandAttribute,无论几次调用,
            //而不同方法对应不同的HystrixCommandAttribute对象,天然的一个policy对象共享
            //因为同一个方法共享一个policy,因此这个CircuitBreaker是针对所有请求的。
            //Attribute也不会在运行时再去改变属性的值,共享同一个policy对象也没问题
            lock (this)
            {
                if (policy == null)
                {
                    policy = 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) => { });

                    if (MaxRetryTimes > 0)//重试
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds)));
                    }

                    if (EnableCircuitBreater)//熔断
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(ExceptionAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak)));
                    }

                    if (TimeOutMilliseconds > 0)//超时
                    {
                        policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic));
                    }
                }
            }

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

            pollyCtx["aspectContext"] = context;

            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);
            }
        }
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            ISyncPolicy policy = Policy.Handle <Exception>().RetryAsync();

            policy.Execute(() =>
            {
                var fallBackMethod    = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod);
                Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters);
                context.ReturnValue   = fallBackResult;
            });
            if (MaxRetryTimes > 0)
            {
                policy = policy.Wrap(Policy.Handle <Exception>().WaitAndRetry(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds)));
            }
            if (EnableCircuitBreaker)
            {
                policy = policy.Wrap(Policy.Handle <Exception>().CircuitBreaker(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(RetryIntervalMilliseconds)));
            }
            if (TimeOutMilliseconds > 0)
            {
                policy = policy.Wrap(Policy.Timeout(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), TimeoutStrategy.Pessimistic));
            }
            //Install-Package Microsoft.Extensions.Caching.Memory
            if (CacheTTLMilliseconds > 0)
            {
                //用类名+方法名+参数的下划线连接起来作为缓存key
                string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType
                                  + "." + context.ServiceMethod + string.Join("_", context.Parameters);
                Object cacheValue;
                //尝试去缓存中获取
                if (memoryCache.TryGetValue(cacheKey, out cacheValue))
                {
                    context.ReturnValue = cacheValue;
                    await Task.FromResult(0);
                }
                else
                {
                    object returnValue = null;
                    policy.Execute(() =>
                    {
                        //执行实际的方法
                        // returnValue = context.Invoke(next);
                        returnValue = next(context);//执行被拦截的方法
                    });
                    using (var cacheEntry = memoryCache.CreateEntry(cacheKey))
                    {
                        cacheEntry.Value = context.ReturnValue;
                        cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds);
                    }
                    await Task.FromResult(returnValue);
                }
            }
            else//如果没有启用缓存,就直接执行业务方法
            {
                object returnValue = null;
                policy.Execute(() =>
                {
                    returnValue = context.Invoke(next);
                });
                await Task.FromResult(returnValue);
            }
        }
Ejemplo n.º 6
0
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            /*
             * share one policy in a instance,because CircuitBreaker require so.
             *
             * the MethodInfo gotten by reflect is always same one,
             * however the instance gotten by reflect is different every time.
             * so we save it in policies with MethodInfo as its key.
             */

            policies.TryGetValue(context.ServiceMethod, out var policy);
            //current method is possible to be called by more than one thread.
            lock (policies)
            {
                if (policy == null)
                {
                    policy = Policy.NoOpAsync();
                    if (EnableCircuitBreaker)
                    {
                        policy = policy.WrapAsync(Policy.Handle <Exception>()
                                                  .CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking,
                                                                       TimeSpan.FromMilliseconds(DurationOfBreak)));
                    }

                    if (TimeOut > 0)
                    {
                        policy = policy.WrapAsync(Policy.TimeoutAsync(
                                                      () => TimeSpan.FromMilliseconds(TimeOut),
                                                      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(async(ctx, t) =>
                    {
                        var aspectContext         = (AspectContext)ctx["aspectContext"];
                        var fallBackMethod        = context.ImplementationMethod.DeclaringType?.GetMethod(FallBackMethod);
                        var fallBackResult        = fallBackMethod?.Invoke(context.Implementation, context.Parameters);
                        aspectContext.ReturnValue = fallBackResult;
                        await Task.CompletedTask;
                    }, async(ex, t) =>
                    {
                        Logger?.LogError(ex, ex.Message);
                        await Task.CompletedTask;
                    });

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

            //transfer local AspectContext to Polly,especially FallbackAsync.this way can avoid troubles in closure
            var pollyCtx = new Context {
                ["aspectContext"] = context
            };

            if (CacheTtl > 0)
            {
                //use assembly.class.method+parameters as cache key
                var cacheKey =
                    $"HystrixMethodCacheManager_Key_{context.ImplementationMethod.DeclaringType.FullName}.{context.ImplementationMethod}{string.Join("_", context.Parameters)}";

                //try to get result from cache firstly.If success return it directly
                if (MemoryCache.TryGetValue(cacheKey, out var cacheValue))
                {
                    context.ReturnValue = cacheValue;
                }
                else
                {
                    //it's not cached currently,just execute the method
                    await policy.ExecuteAsync(ctx => next(context), pollyCtx);

                    //cache it
                    using (var cacheEntry = MemoryCache.CreateEntry(cacheKey))
                    {
                        cacheEntry.Value = context.ReturnValue;
                        cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTtl);
                    }
                }
            }
            else //disabled cache,just execute the method directly
            {
                await policy.ExecuteAsync(ctx => next(context), pollyCtx);
            }
        }