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(); }
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); }
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); } }
/// <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 }
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(); }
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); }
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); }
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); } }
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); } }