From 32be755dae861c379d8fd6548256474405efec5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Rodr=C3=ADguez?= Date: Wed, 1 Sep 2021 06:05:45 -0700 Subject: [PATCH] Wait for GetOrAddAsync factory to return before reading from AbsoluteExpirationRelativeToNow (#160) * fix: await addItemFactory before calling SetAbsoluteExpirationFromRelative allows AbsoluteExpiration to be set properly when factories are long-running and a relative expiration is specified fixes #148 * test: verify that AbsoluteExpiration is set properly from a relative expiration when a factory is long-running * test: improve unit test names --- .../CachingServiceMemoryCacheProviderTests.cs | 42 +++++++++++++++++++ LazyCache/CachingService.cs | 6 +-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs b/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs index 3de5c05..a346ae3 100644 --- a/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs +++ b/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs @@ -790,6 +790,48 @@ public async Task GetOrAddAsyncWithAbsoluteOffsetExpiryInTheDelegateUsingTimeSpa Assert.That(expiredResult, Is.Null); } + [Test] + public async Task GetOrAddAsyncWithAbsoluteOffsetExpiryInTheDelegateAfterLongRunningTaskDoesExpireItems() + { + var millisecondsCacheDuration = 100; + var validResult = await sut.GetOrAddAsync( + TestKey, + async entry => + { + await Task.Delay(50); + entry.SetAbsoluteExpiration(DateTimeOffset.Now.AddMilliseconds(millisecondsCacheDuration)); + return new ComplexTestObject(); + } + ); + // pass expiry time with a delay + Thread.Sleep(TimeSpan.FromMilliseconds(millisecondsCacheDuration + 50)); + var expiredResult = sut.Get(TestKey); + + Assert.That(validResult, Is.Not.Null); + Assert.That(expiredResult, Is.Null); + } + + [Test] + public async Task GetOrAddAsyncWithAbsoluteOffsetExpiryInTheDelegateUsingTimeSpanAfterLongRunningTaskDoesExpireItems() + { + var millisecondsCacheDuration = 100; + var validResult = await sut.GetOrAddAsync( + TestKey, + async entry => + { + await Task.Delay(50); + entry.SetAbsoluteExpiration(TimeSpan.FromMilliseconds(millisecondsCacheDuration)); + return new ComplexTestObject(); + } + ); + // pass expiry time with a delay + Thread.Sleep(TimeSpan.FromMilliseconds(millisecondsCacheDuration + 50)); + var expiredResult = sut.Get(TestKey); + + Assert.That(validResult, Is.Not.Null); + Assert.That(expiredResult, Is.Null); + } + [Test] public void GetOrAddWithCancellationExpiryBasedOnTimerAndCallbackInTheDelegateDoesExpireItemsAndFireTheCallback() { diff --git a/LazyCache/CachingService.cs b/LazyCache/CachingService.cs index 8eafe70..df091de 100644 --- a/LazyCache/CachingService.cs +++ b/LazyCache/CachingService.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using LazyCache.Providers; using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.Primitives; namespace LazyCache { @@ -201,9 +200,9 @@ public virtual async Task GetOrAddAsync(string key, Func - new AsyncLazy(() => + new AsyncLazy(async () => { - var result = addItemFactory(entry); + var result = await addItemFactory(entry).ConfigureAwait(false); SetAbsoluteExpirationFromRelative(entry); EnsureEvictionCallbackDoesNotReturnTheAsyncOrLazy(entry.PostEvictionCallbacks); return result; @@ -242,7 +241,6 @@ object CacheFactory(ICacheEntry entry) => result = GetValueFromAsyncLazy(cacheItem, out _ /* we just evicted so type change cannot happen this time */); } - if (result.IsCanceled || result.IsFaulted) CacheProvider.Remove(key);