I don't understand how sliding expiration is supposed to work in System.Runtime.Caching.MemoryCache with .NET 4.0.
According to the documentation, the expiring timespan is "A span of time within which a cache entry must be accessed before the cache entry is evicted from the cache."
However the following unit test fails:
private const string AnyKey = "key";
private const string AnyValue = "value";
private readonly TimeSpan timeout = TimeSpan.FromSeconds(0.5);
private void WaitSixtyPercentOfTheTimeout()
{
Thread.Sleep(TimeSpan.FromSeconds(timeout.TotalSeconds*0.6));
}
[Test]
public void Get_RefreshesTimeoutOfSlidingExpiration()
{
var cache = MemoryCache.Default;
cache.Set(AnyKey, AnyValue, new CacheItemPolicy {SlidingExpiration = timeout});
WaitSixtyPercentOfTheTimeout();
cache[AnyKey].Should().Be(AnyValue);
WaitSixtyPercentOfTheTimeout();
cache[AnyKey].Should().Be(AnyValue);
}
private void UpdateCallback(CacheEntryUpdateArguments arguments)
{
}
Per coincidence, I made a small change which fixed this issue. However, does anybody now if it is a bug or a feature?
Once, the UpdateCallBack is set, expiration works as expected:
// [...]
[Test]
public void Get_RefreshesTimeoutOfSlidingExpiration()
{
var cache = MemoryCache.Default;
cache.Set(AnyKey, AnyValue, new CacheItemPolicy {SlidingExpiration = timeout, UpdateCallback = UpdateCallback});
WaitSixtyPercentOfTheTimeout();
cache[AnyKey].Should().Be(AnyValue);
WaitSixtyPercentOfTheTimeout();
cache[AnyKey].Should().Be(AnyValue);
}
private void UpdateCallback(CacheEntryUpdateArguments arguments)
{
}
Make the timeout longer seems to fix the problem. Make it 2 seconds works on my machine:
private readonly TimeSpan timeout = TimeSpan.FromSeconds(2);
I guess the current caching mechanism is not very accurate in timing, but in practice you wouldn't keep cache for half a second anyway.