コード例 #1
0
        public void Put_should_put_item_using_passed_sliding_ttl_zero()
        {
#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();

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);

            TimeSpan minExpiration =
#if PORTABLE
                TimeSpan.FromMilliseconds(1) // This is the minimum permitted sliding ttl for .NetStandard
#else
                TimeSpan.Zero
#endif
            ;

            Ttl ttl = new Ttl(minExpiration, false);
            provider.Put(key, value, ttl);

            Thread.Sleep(TimeSpan.FromMilliseconds(10));

#if PORTABLE
            object got;
            memoryCache.TryGetValue(key, out got);
#else
            object got = memoryCache[key];
#endif
            got.Should().BeNull();
        }
コード例 #2
0
        public void Put_should_put_item_using_passed_sliding_ttl_maxvalue()
        {
#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();

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);

            TimeSpan maxSlidingExpiration =
#if PORTABLE
                TimeSpan.MaxValue
#else
                TimeSpan.FromDays(365) // This is the maximum permitted sliding ttl for .NetFramework4.0 and 4.5 MemoryCache.
#endif
            ;

            Ttl ttl = new Ttl(maxSlidingExpiration, true);
            provider.Put(key, value, ttl);

#if PORTABLE
            object got;
            memoryCache.TryGetValue(key, out got);
#else
            object got = memoryCache[key];
#endif
            got.Should().BeSameAs(value);
        }
コード例 #3
0
        public void Put_should_put_item_using_passed_sliding_ttl()
        {
#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

            TimeSpan shimTimeSpan = TimeSpan.FromSeconds(1); // If test fails transiently in different environments, consider increasing shimTimeSpan.

            string key   = "anything";
            object value = new object();

            // Place an item in the cache that should last for only 2x shimTimespan
            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);
            Ttl ttl = new Ttl(shimTimeSpan + shimTimeSpan, true);
            provider.Put(key, value, ttl);

            // Prove that we can repeatedly get it from the cache over a 5x shimTimespan period, due to repeated access.

            for (int i = 0; i < 5; i++)
            {
#if PORTABLE
                object got;
                memoryCache.TryGetValue(key, out got);
#else
                object got = memoryCache[key];
#endif

                got.Should().BeSameAs(value, $"at iteration {i}");

                Thread.Sleep(shimTimeSpan);
            }
        }
コード例 #4
0
        /// <summary>
        /// Gets a value from cache.
        /// </summary>
        /// <param name="key">The cache key.</param>
        /// <returns>The value from cache; or null, if none was found.</returns>
        public object Get(String key)
        {
#if PORTABLE
            object value;
            if (_cache.TryGetValue(key, out value))
            {
                return(value);
            }
            return(null);
#else
            return(_cache.Get(key));
#endif
        }
コード例 #5
0
        public void Put_should_put_item_using_passed_nonsliding_ttl()
        {
#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

            TimeSpan shimTimeSpan = TimeSpan.FromSeconds(0.1); // If test fails transiently in different environments, consider increasing shimTimeSpan.

            string key   = "anything";
            object value = new object();

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);
            Ttl ttl = new Ttl(shimTimeSpan, false);
            provider.Put(key, value, ttl);

            // Initially (before ttl expires), should be able to get value from cache.
#if PORTABLE
            object got;
            memoryCache.TryGetValue(key, out got);
#else
            object got = memoryCache[key];
#endif
            got.Should().BeSameAs(value);

            // Wait until the TTL on the cache item should have expired.
            Thread.Sleep(shimTimeSpan + shimTimeSpan);

#if PORTABLE
            memoryCache.TryGetValue(key, out got);
#else
            got = memoryCache[key];
#endif

            got.Should().NotBeSameAs(value);
            got.Should().BeNull();
        }
コード例 #6
0
        public void Put_should_put_item_using_passed_nonsliding_ttl_maxvalue()
        {
#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();

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);
            Ttl ttl = new Ttl(TimeSpan.MaxValue, false);
            provider.Put(key, value, ttl);

#if PORTABLE
            object got;
            memoryCache.TryGetValue(key, out got);
#else
            object got = memoryCache[key];
#endif
            got.Should().BeSameAs(value);
        }
コード例 #7
0
        public void Put_should_put_item_into_configured_MemoryCacheImplementation()
        {
#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   = Guid.NewGuid().ToString();
            object value = new object();

            MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache);
            Ttl ttl = new Ttl(TimeSpan.FromSeconds(10));
            provider.Put(key, value, ttl);

#if PORTABLE
            object got;
            memoryCache.TryGetValue(key, out got);
#else
            object got = memoryCache[key];
#endif

            got.Should().BeSameAs(value);
        }
コード例 #8
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 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);
            }
        }
コード例 #9
0
        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);
            }
        }
コード例 #10
0
        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);
            }
        }
コード例 #11
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);
            }
        }