I am using LazyCache and want to have cache refreshed e.g. every hour, but ideally I want the first caller after the cache item expired do not wait for cache reloaded. I wrote the following
public async Task<List<KeyValuePair<string, string>>> GetCarriersAsync()
{
var options = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = new TimeSpan(1,0,0),// consider to config
}.RegisterPostEvictionCallback(
async (key, value, reason, state) =>
{
await GetCarriersAsync();//will save to cache
_logger.LogInformation("Carriers are reloaded: " );
});
Func<Task<List<KeyValuePair<string, string>>>> cacheableAsyncFunc = () => GetCarriersFromApi();
var cachedCarriers = await _cache.GetOrAddAsync($"Carriers", cacheableAsyncFunc, options);
return cachedCarriers;
}
However RegisterPostEvictionCallback is not called when cache item is expired, but only when the next request to the item occurred (and the caller need to wait for a lengthy operation).
The thread Expiration almost never happens on it's own in the background #248 explains that this is by design, and suggests workaround to specify CancellationTokenSource.CancelAfter(TimeSpan.FromHours(1)) instead of SetAbsoluteExpiration.
Unfortunately LazyCache.GetOrAddAsync doesn’t have CancellationToken as a parameter. What is the best way to trigger reload of cache on a scheduled time with minimal waiting time for the first user?
I found the similar question In-Memory Caching with auto-regeneration on ASP.Net Core that suggested to call the
AddExpirationToken(new CancellationChangeToken(new CancellationTokenSource(_options.ReferenceDataRefreshTimeSpan).Token)
.I tried it, but didn't make it working. However the same answer had alternative(and recommended) option by using timer. I've created a class RefreshebleCache that I am using for different cachable options like the following:
The RefreshebleCache implementation:
}