Reputation: 81
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;
using Xunit;
namespace Demo.Caching.Test
{
class MemoryCacheManagerTest
{
[Fact]
public void Test()
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.SlidingExpiration = TimeSpan.FromSeconds(1);
MemoryCache.Default.Set("cacheKey4", 4, policy);
Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
System.Threading.Thread.Sleep(600);
Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
System.Threading.Thread.Sleep(600);
Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
// Here I get error
// Expected: 4, Actual: (null)
System.Threading.Thread.Sleep(1000);
Assert.Null(MemoryCache.Default.Get("cacheKey4"));
}
}
}
Upvotes: 8
Views: 3123
Reputation: 156624
This is not, as the other answers have said, due to Thread.Sleep() taking longer than expected.
MemoryCache
appears to be pretty imprecise with its sliding timer. I'm guessing that this is so they can avoid locking, and keep up the cache's performance.
So I guess the lesson is to not rely on sliding expirations to work correctly for values under 2 seconds. This may have something to do with the PollingInterval
being set to 2 seconds.
Code:
var span = TimeSpan.FromSeconds(1); // change as necessary
var sw = new Stopwatch();
var cache = new MemoryCache("testcache");
sw.Start();
cache.Add("test", "hello", new CacheItemPolicy{SlidingExpiration = span});
Console.WriteLine(sw.ElapsedMilliseconds);
for (int i = 0; i < 40; i++)
{
Console.WriteLine(sw.ElapsedMilliseconds + ": " + cache.Get("test"));
Thread.Sleep(50); // change as necessary
}
Upvotes: 4
Reputation: 100361
I had the same problem. But actually the problem is what @Colin said. The Thread.Sleep
is taking over than a second.
So I made a test with a bigger delay
[TestMethod]
public void Sliding()
{
MemoryCache.Default.Add("test", 1,
new CacheItemPolicy
{
SlidingExpiration = new TimeSpan(0, 0, seconds: 5)
});
for (int i = 0; i < 15; ++i)
{
Assert.IsNotNull(MemoryCache.Default.Get("test"));
Thread.Sleep(700);
}
}
And it passed. I am not sure if it will always work -- probably not -- but I just confirmed that the sliding actually works.
Upvotes: 0
Reputation: 19175
Possibly the reason is that Sleep is non-deterministic. It does not pause your thread for 600 milliseconds. It pauses the thread for at least 600 ms. It could very well go over the 1 second sliding expiry you've set without you realising.
Upvotes: 4