1

So I have an issue when trying to cache on the first request a user sends and then use the cached data in all following requests. A lot of data is fetched on the first request and it's pretty resource heavy so that's why I'm caching it.

The issue is that the user/frontend will on some pages send multiple requests simultaneously. This triggers the resource heavy mechanism to create the cache entry multiple times. Is there some good way to "consolidate" these requests to only trigger the caching logic once?

Currently it works like this:

Name Time Triggers recaching logic?
Request 1 00:00 Yes <-- Only this one should fetch the resources to cache
Request 2 00:00 Yes <-- This should wait for cache to be populatd by Request 1
Request 3 00:00 Yes <-- This should wait for cache to be populated by Request 1
Request 4 00:05 No
Request 5 00:15 No

I don't think my actual code is very relevant since I'm more looking for a general concept of this. I've tried looking around for solutions but can't find anything applicable, and I've also attempted to put a dictionary of <cacheKey, cachingTask> that contains the caching tasks while they're being processed but it seems the requests are too close in time for this to work as well.

Mimir
  • 53
  • 3
  • What caching mechanism are you using? [MemoryCache](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)? [LazyCache](https://www.nuget.org/packages/LazyCache)? Something custom? – Theodor Zoulias Dec 12 '22 at 12:10
  • I'm using a memory cache. – Mimir Dec 12 '22 at 12:17
  • Do you mean specifically the [`Microsoft.Extensions.Caching.Memory.MemoryCache`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.memory.memorycache) class? – Theodor Zoulias Dec 12 '22 at 12:37
  • Correct @TheodorZoulias. However the [LazyCache](https://www.nuget.org/packages/LazyCache) project you referenced seem to maybe be a good fit for me here.. Specifically according to this line: "... and provides a thread safe cache implementation that guarantees to only execute your cachable delegates once ..." – Mimir Dec 12 '22 at 12:43
  • 1
    Related question: [Stop Reentrancy on MemoryCache Calls](https://stackoverflow.com/questions/65640644/stop-reentrancy-on-memorycache-calls). An answer there suggests to use the LazyCache library, with which I agree. Microsoft's `MemoryCache` class has not an API sophisticated enough that would allow to solve optimally this problem. – Theodor Zoulias Dec 12 '22 at 12:48
  • 1
    After some light testing the LazyCache library seems to be working very well for me so far. I appreciate the answer! – Mimir Dec 12 '22 at 12:49
  • Related API suggestion on GitHub: [GetOrCreateExclusive() and GetOrCreateExclusiveAsync(): Exclusive versions of GetOrCreate() and GetOrCreateAsync()](https://github.com/dotnet/runtime/issues/36500). It was not accepted. – Theodor Zoulias Dec 12 '22 at 13:17
  • You could also consider using Stephen Cleary's [`AsyncCache`](https://gist.github.com/StephenCleary/39a2cd0aa3c705a984a4dbbea8275fe9). At the time being it's just a .cs file, not a NuGet package. Both implementations are wrapping a `Microsoft.Extensions.Caching.Memory.MemoryCache`, and use `lock`s to prevent race conditions in the `GetOrCreateAsync` method. – Theodor Zoulias Dec 14 '22 at 11:16

0 Answers0