VahidN / EFSecondLevelCache.Core

Entity Framework Core Second Level Caching Library
Apache License 2.0
326 stars 50 forks source link

Cache Doesn't Appear to Flush After SaveChanges() #32

Closed twurm closed 5 years ago

twurm commented 5 years ago

Summary of the issue

We are running into what appears to be a cache flush issue when a new record is added. In our case we query a table for a record something simple:

var debugger = new EFCacheDebugInfo();
(IQueryable).Where(x=>x.Column1 == "ABC" && x.Column2="XYZ").Cacheable(debugger).FirstOrDefault()

The result is null which is expected, since the result is null we go to another table and load the record. SaveChanges is called and InvalidateCacheDependencies(changedEntityNames); fires as expected, changedEntityNames contains the changed entity. We even tried using ClearAllCachedEntries() but the result was the same.

Later when we query for that record again the we are getting null back still and debugger.IsCacheHit == true. We are expecting IsCacheHit to be false and the query to go back to the database and get the newly added entity.

If we restart the app after the record is added everything works correctly, which is why we are leaning towards the cache flushing.

The app in question is a .Net Core Console app (v.2.2) using a .Net Standard 2.0 library dll where the caching takes place. The dll is a plugin, and loaded via MEF.

We have configured the second level cache in ConfigureServices like so:

// Add an in-memory cache service provider 
services.AddEFSecondLevelCache();
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
services.AddSingleton(typeof(ICacheManagerConfiguration),
   new CacheManager.Core.ConfigurationBuilder("Mx.DataLoad")
      .WithJsonSerializer()
      .WithMicrosoftLogging(loggerFactory)
      .WithMicrosoftMemoryCacheHandle()
      .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(Configuration.GetValue("Caching:ExpirationInMinutes", 60)))
   .Build());

// Additional code to spin up our ServiceProvider
var serviceProvider = services.BuildServiceProvider();
EFServiceProvider.ApplicationServices = serviceProvider;

Environment

The in-use version: 1.7.1
Operating system: Windows 10
IDE: VS 2017

Packages

<PackageReference Include="EFSecondLevelCache.Core" Version="1.7.1" />
<PackageReference Include="CacheManager.Core" Version="1.2.0" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Caching.Memory" Version="1.2.0" />
<PackageReference Include="CacheManager.Serialization.Json" Version="1.2.0" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.2.0" />

Questions

Is there a way to visualize the cache so we can see what is going on at each step?

Any suggestions on where to look to isolate the issue?

VahidN commented 5 years ago
twurm commented 5 years ago

@VahidN thanks for the suggestion, I didn't have Redis available so I swapped out the WithMicrosoftMemoryCacheHandle for a WithDictionaryHandle and it worked as expected. So the issue seems to be with the MicrosoftMemoryCacheHandle. Any ideas of performance implications? If not I'll followup with the CacheManager folks.

twurm commented 5 years ago

@VahidN I figured it out, I was using '.WithMicrosoftMemoryCacheHandle()' but when I switched to 'WithMicrosoftMemoryCacheHandle("AnyString")' things worked correctly. A full example is below.

// Add an in-memory cache service provider 
services.AddEFSecondLevelCache();
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
services.AddSingleton(typeof(ICacheManagerConfiguration),
   new CacheManager.Core.ConfigurationBuilder("Mx.DataLoad")
      .WithJsonSerializer()
      .WithMicrosoftLogging(loggerFactory)
      //.WithMicrosoftMemoryCacheHandle() this didn't work
      .WithMicrosoftMemoryCacheHandle("AnyString") // This works perfectly
      .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(Configuration.GetValue("Caching:ExpirationInMinutes", 60)))
   .Build());

// Additional code to spin up our ServiceProvider
var serviceProvider = services.BuildServiceProvider();
EFServiceProvider.ApplicationServices = serviceProvider;
twurm commented 5 years ago

@VahidN once we rolled out the fix we still see it in Test, must have been pilot error in dev testing.+

VahidN commented 5 years ago

Hopefully V1.8.1 fixes this issue. Now caching mechanism acts as a true singleton!

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related problems.