/// <summary> /// Gets a TTL for a cacheable item, given the current execution context. /// </summary> /// <param name="context">The execution context.</param> /// <returns>A <see cref="Ttl"/> representing the remaining Ttl of the cached item.</returns> public Ttl GetTtl(Context context) { TimeSpan untilPointInTime = absoluteExpirationTime.Subtract(SystemClock.DateTimeOffsetUtcNow()); TimeSpan remaining = untilPointInTime > TimeSpan.Zero ? untilPointInTime : TimeSpan.Zero; return(new Ttl(remaining, false)); }
/// <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 }
public async Task Should_execute_delegate_and_put_value_in_cache_but_when_it_expires_execute_delegate_again() { const string valueToReturn = "valueToReturn"; const string operationKey = "SomeOperationKey"; IAsyncCacheProvider stubCacheProvider = new StubCacheProvider(); TimeSpan ttl = TimeSpan.FromMinutes(30); var cache = Policy.CacheAsync <string>(stubCacheProvider, ttl); (bool cacheHit1, object fromCache1) = await stubCacheProvider.TryGetAsync(operationKey, CancellationToken.None, false).ConfigureAwait(false); cacheHit1.Should().BeFalse(); fromCache1.Should().BeNull(); int delegateInvocations = 0; Func <Context, Task <string> > func = async ctx => { delegateInvocations++; await TaskHelper.EmptyTask.ConfigureAwait(false); return(valueToReturn); }; DateTimeOffset fixedTime = SystemClock.DateTimeOffsetUtcNow(); SystemClock.DateTimeOffsetUtcNow = () => fixedTime; // First execution should execute delegate and put result in the cache. (await cache.ExecuteAsync(func, new Context(operationKey)).ConfigureAwait(false)).Should().Be(valueToReturn); delegateInvocations.Should().Be(1); (bool cacheHit2, object fromCache2) = await stubCacheProvider.TryGetAsync(operationKey, CancellationToken.None, false).ConfigureAwait(false); cacheHit2.Should().BeTrue(); fromCache2.Should().Be(valueToReturn); // Second execution (before cache expires) should get it from the cache - no further delegate execution. // (Manipulate time so just prior cache expiry). SystemClock.DateTimeOffsetUtcNow = () => fixedTime.Add(ttl).AddSeconds(-1); (await cache.ExecuteAsync(func, new Context(operationKey)).ConfigureAwait(false)).Should().Be(valueToReturn); delegateInvocations.Should().Be(1); // Manipulate time to force cache expiry. SystemClock.DateTimeOffsetUtcNow = () => fixedTime.Add(ttl).AddSeconds(1); // Third execution (cache expired) should not get it from the cache - should cause further delegate execution. (await cache.ExecuteAsync(func, new Context(operationKey)).ConfigureAwait(false)).Should().Be(valueToReturn); delegateInvocations.Should().Be(2); }
public (bool, object) TryGet(string key) { if (cachedValues.ContainsKey(key)) { if (SystemClock.DateTimeOffsetUtcNow() < cachedValues[key].Expiry) { return(true, cachedValues[key].Value); } else { cachedValues.Remove(key); } } return(false, null); }
public void Should_return_configured_timespan_from_time_requested() { DateTimeOffset fixedTime = SystemClock.DateTimeOffsetUtcNow(); TimeSpan ttl = TimeSpan.FromSeconds(30); TimeSpan delay = TimeSpan.FromSeconds(5); RelativeTtl ttlStrategy = new RelativeTtl(ttl); SystemClock.DateTimeOffsetUtcNow = () => fixedTime.Add(delay); Ttl retrieved = ttlStrategy.GetTtl(new Context("someExecutionKey"), null); retrieved.Timespan.Should().BeCloseTo(ttl); retrieved.SlidingExpiration.Should().BeFalse(); }
public object Get(string key) { if (cachedValues.ContainsKey(key)) { if (SystemClock.DateTimeOffsetUtcNow() < cachedValues[key].Expiry) { return(cachedValues[key].Value); } else { cachedValues.Remove(key); } } return(null); }
public void Should_execute_delegate_and_put_value_in_cache_but_when_it_expires_execute_delegate_again() { const string valueToReturn = "valueToReturn"; const string operationKey = "SomeOperationKey"; ISyncCacheProvider stubCacheProvider = new StubCacheProvider(); TimeSpan ttl = TimeSpan.FromMinutes(30); CachePolicy <string> cache = Policy.Cache <string>(stubCacheProvider, ttl); (bool cacheHit1, object fromCache1) = stubCacheProvider.TryGet(operationKey); cacheHit1.Should().BeFalse(); fromCache1.Should().BeNull(); int delegateInvocations = 0; Func <Context, string> func = _ => { delegateInvocations++; return(valueToReturn); }; DateTimeOffset fixedTime = SystemClock.DateTimeOffsetUtcNow(); SystemClock.DateTimeOffsetUtcNow = () => fixedTime; // First execution should execute delegate and put result in the cache. cache.Execute(func, new Context(operationKey)).Should().Be(valueToReturn); delegateInvocations.Should().Be(1); (bool cacheHit2, object fromCache2) = stubCacheProvider.TryGet(operationKey); cacheHit2.Should().BeTrue(); fromCache2.Should().Be(valueToReturn); // Second execution (before cache expires) should get it from the cache - no further delegate execution. // (Manipulate time so just prior cache expiry). SystemClock.DateTimeOffsetUtcNow = () => fixedTime.Add(ttl).AddSeconds(-1); cache.Execute(func, new Context(operationKey)).Should().Be(valueToReturn); delegateInvocations.Should().Be(1); // Manipulate time to force cache expiry. SystemClock.DateTimeOffsetUtcNow = () => fixedTime.Add(ttl).AddSeconds(1); // Third execution (cache expired) should not get it from the cache - should cause further delegate execution. cache.Execute(func, new Context(operationKey)).Should().Be(valueToReturn); delegateInvocations.Should().Be(2); }
/// <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) { TimeSpan remaining = DateTimeOffset.MaxValue - SystemClock.DateTimeOffsetUtcNow(); MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); if (ttl.SlidingExpiration) { options.SlidingExpiration = ttl.Timespan < remaining ? ttl.Timespan : remaining; } else { if (ttl.Timespan == TimeSpan.MaxValue) { options.AbsoluteExpiration = DateTimeOffset.MaxValue; } else { options.AbsoluteExpirationRelativeToNow = ttl.Timespan < remaining ? ttl.Timespan : remaining; } } _cache.Set(key, value, options); }
public CacheItem(object value, Ttl ttl) { Expiry = DateTimeOffset.MaxValue - SystemClock.DateTimeOffsetUtcNow() > ttl.Timespan ? SystemClock.DateTimeOffsetUtcNow().Add(ttl.Timespan) : DateTimeOffset.MaxValue; Value = value; }
public void Should_return_zero_ttl_if_configured_to_expire_in_past() { AbsoluteTtl ttlStrategy = new AbsoluteTtl(SystemClock.DateTimeOffsetUtcNow().Subtract(TimeSpan.FromTicks(1))); ttlStrategy.GetTtl(new Context("someExecutionKey"), null).Timespan.Should().Be(TimeSpan.Zero); }
protected static void AdvanceClock(TimeSpan advance) { DateTimeOffset now = SystemClock.DateTimeOffsetUtcNow(); SystemClock.DateTimeOffsetUtcNow = () => now + advance; }