Search code examples
c#.net-corememorycache

Where/how do I set the timeout for MemoryCache?


I am setting up my MemoryCache as follows:

DataCache = new MemoryCache(new MemoryCacheOptions
{
    ExpirationScanFrequency = TimeSpan.FromMinutes(5)
});
CacheOptions = new MemoryCacheEntryOptions
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
};

And then using it as follows:

DataCache.Set(Keys.Users, listAllUsers, CacheOptions);

Is this correct? It seems weird to me that I have to set it in 2 places.


Solution

  • There are two parts to expiration (by time) of a cache line:

    1. The timespan after which the cache line "expires". In this case that means it becomes eligible for removal (aka "eviction"). This is a passive thing - there is no piece of code that actively sets the cache line from valid to expired, it is just a timestamp becoming "older" than "now".

    2. The cycle time at which an active process is executed, that scans the cache for expired cache lines and removes them.

    The combination of both result in the actual expiration and removal timespan of an individual cache line. If we take an example of expiration at 5 minutes from insertion time and a scan cycle every 15 seconds, then in best (or short) case, the cycle runs exactly so the expiration happens at the same time and the line is removed immediately after the 5 mins. The worst (or longest) case would be that the scan cycle finishes right before expiration and the cache line lives on to 5 minutes and 15 seconds (everything +/- system timing / clock inaccuracies).

    If you set both to 5 minutes, you will end up with single cache lines living any time between 5 minutes and 10 minutes. (Statistically speaking, assuming insertions are normal distributed.)

    For future readers of this answer: Mind this important notice in the docs

    There are two MemoryCache classes within .NET, one in the System.Runtime.Caching namespace and the other in the Microsoft.Extensions.Caching namespace

    (emphasis by me)

    Also mind, that there is also a SlidingExpiration, which is not addressed in the question and neither in this answer. The SlidingExpiration will extend the expiration threshold when the cache line is hit. Recommendation if using it is to set both sliding and absolute, to avoid that a frequently hit cache line never actually gets evicted (which can cause problems).