alastairtree / LazyCache

An easy to use thread safe in-memory caching service with a simple developer friendly API for c#
https://nuget.org/packages/LazyCache
MIT License
1.72k stars 159 forks source link

Absolute expiration does not work v2.4.0 #170

Open PatryxCShark opened 2 years ago

PatryxCShark commented 2 years ago

Describe the bug Absolute expiration seems to not work. In unit tests (C#, Windows) it's ok but after deploying on Linux server, each time function to load data is called.

To Reproduce

Let's say class: MyCachingManager:

        private MemoryCacheEntryOptions GetEntryCacheOptions()
        {
            return new MemoryCacheEntryOptions()
                .SetPriority(CacheItemPriority.Normal)
                .SetAbsoluteExpiration(TimeSpan.FromMinutes(3))
                .AddExpirationToken(new CancellationChangeToken(_myCacheCancellationTokenSource.Token));
        }
        public Task<ICollection<MyClass>> GetOrAddMyClassAsync(string key, Func<Task<ICollection<MyClass>>> addItemFactory)
        {
            return _cache.GetOrAddAsync(jey, addItemFactory, GetEntryCacheOptions());
        } 

And example of using:

            async Task<ICollection<MyClass>> LoadMyData()
            {
                var tc = new List<MyClass>() { new MyClass(), new MyClass() };

                return tc;
            }

            var claims = await _myCachingManager.GetOrAddMyClassAsync("userX", LoadMyData);

Any idea why every time addItemFactory is called (LoadMyData)? When I used MemoryCache there was no problem and it worked as expected (expiry every 3 minutes).

Expected behavior Entry in Lazy Cache should expiry 3 minutes after last loading data into cache.

Framework and Platform

PatryxCShark commented 2 years ago

I found the problem. It seems that the problem is different than I described above and connected with: .AddExpirationToken(new CancellationChangeToken(_myCacheCancellationTokenSource.Token))

_myCacheCancellationTokenSource is added as singleton and read from constructor (DI).

When I call _myCacheCancellationTokenSource.Cancel() all entries should dissapear from cache and it works as expected. But when they are load again into cache, they are not saved in cache because _myCacheCancellationTokenSource has cancel state. I want to have "refreshed" (not canceled) token for new entries.

Any idea how I can achieve scenario:

  1. add entries in cache (ask for a given keys)
  2. call '_myCacheCancellationTokenSource.Cancel()' to clear entries done before
  3. ask for data in key what forces to load data into cache again but to preserve data in cache (currently not saved or automatically deleted because of cancelling _myCacheCancellationTokenSource)
  4. has possibility to cancel token '_myCacheCancellationTokenSource.Cancel()' to remove data from point 3?