Skip to content

Commit

Permalink
Wait for GetOrAddAsync factory to return before reading from Absolute…
Browse files Browse the repository at this point in the history
…ExpirationRelativeToNow (#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
  • Loading branch information
allanrodriguez committed Sep 1, 2021
1 parent b6e6f74 commit 32be755
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
42 changes: 42 additions & 0 deletions LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ComplexTestObject>(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<ComplexTestObject>(TestKey);

Assert.That(validResult, Is.Not.Null);
Assert.That(expiredResult, Is.Null);
}

[Test]
public void GetOrAddWithCancellationExpiryBasedOnTimerAndCallbackInTheDelegateDoesExpireItemsAndFireTheCallback()
{
Expand Down
6 changes: 2 additions & 4 deletions LazyCache/CachingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Threading.Tasks;
using LazyCache.Providers;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;

namespace LazyCache
{
Expand Down Expand Up @@ -201,9 +200,9 @@ public virtual async Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task
while (Interlocked.CompareExchange(ref keyLocks[hash], 1, 0) == 1) { Thread.Yield(); }

object CacheFactory(ICacheEntry entry) =>
new AsyncLazy<T>(() =>
new AsyncLazy<T>(async () =>
{
var result = addItemFactory(entry);
var result = await addItemFactory(entry).ConfigureAwait(false);
SetAbsoluteExpirationFromRelative(entry);
EnsureEvictionCallbackDoesNotReturnTheAsyncOrLazy<T>(entry.PostEvictionCallbacks);
return result;
Expand Down Expand Up @@ -242,7 +241,6 @@ object CacheFactory(ICacheEntry entry) =>
result = GetValueFromAsyncLazy<T>(cacheItem, out _ /* we just evicted so type change cannot happen this time */);
}


if (result.IsCanceled || result.IsFaulted)
CacheProvider.Remove(key);

Expand Down

0 comments on commit 32be755

Please sign in to comment.