gpt4 book ai didi

caching - 在ASP.Net Core上具有自动重新生成的内存中缓存

转载 作者:行者123 更新时间:2023-12-04 13:57:09 24 4
gpt4 key购买 nike

我想没有内置的方法可以做到这一点:

我有一些缓存的数据,这些数据必须始终是最新的(间隔为几十分钟)。它的生成大约需要1-2分钟,因此有时会导致超时请求。

为了优化性能,我使用Cache.GetOrCreateAsync将其放入内存缓存中,因此我确定可以在40分钟内快速访问数据。但是,缓存过期仍然需要时间。

我希望有一种机制可以在数据过期之前自动刷新数据,因此用户不会受到刷新的影响,并且在刷新过程中仍然可以访问“旧数据”。

实际上,它将添加一个“过期前”过程,该过程将避免数据过期达到其期限。

我觉得这不是默认IMemoryCache缓存的功能,但是我可能错了吗?
是否存在?如果没有,您将如何开发此功能?

我正在考虑使用PostEvictionCallbacks,将条目设置为在35分钟后删除,这将触发更新方法(它涉及DbContext)。

最佳答案

这是我解决的方法:

Web请求调用的部分(“Create”方法应仅在第一次调用)。

var allPlaces = await Cache.GetOrCreateAsync(CACHE_KEY_PLACES
, (k) =>
{
k.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(40);
UpdateReset();
return GetAllPlacesFromDb();
});

然后是魔术(本可以通过计时器实现的,但不想在那里处理计时器)

// This method adds a trigger to refresh the data from background
private void UpdateReset()
{
var mo = new MemoryCacheEntryOptions();
mo.RegisterPostEvictionCallback(RefreshAllPlacessCache_PostEvictionCallback);
mo.AddExpirationToken(new CancellationChangeToken(new CancellationTokenSource(TimeSpan.FromMinutes(35)).Token));
Cache.Set(CACHE_KEY_PLACES_RESET, DateTime.Now, mo);
}

// Method triggered by the cancellation token that triggers the PostEvictionCallBack
private async void RefreshAllPlacesCache_PostEvictionCallback(object key, object value, EvictionReason reason, object state)
{
// Regenerate a set of updated data
var places = await GetLongGeneratingData();
Cache.Set(CACHE_KEY_PLACES, places, TimeSpan.FromMinutes(40));

// Re-set the cache to be reloaded in 35min
UpdateReset();
}

因此,缓存会通过触发触发逐出方法的取消 token 获得两个条目,第一个条目包含数据,在40分钟后过期,第二个条目在35分钟后过期。
此回调将在数据过期之前刷新数据。

请记住,这将使网站保持唤醒状态,并且即使不使用也会占用内存。

** *更新使用计时器* **

下列类(class)注册为单例。传递DbContextOptions而不是DbContext来创建具有正确作用域的DbContext。

public class SearchService
{
const string CACHE_KEY_ALLPLACES = "ALL_PLACES";
protected readonly IMemoryCache Cache;
private readonly DbContextOptions<AppDbContext> AppDbOptions;
public SearchService(
DbContextOptions<AppDbContext> appDbOptions,
IMemoryCache cache)
{
this.AppDbOptions = appDbOptions;
this.Cache = cache;
InitTimer();
}
private void InitTimer()
{
Cache.Set<AllEventsResult>(CACHE_KEY_ALLPLACESS, new AllPlacesResult() { Result = new List<SearchPlacesResultItem>(), IsBusy = true });

Timer = new Timer(TimerTickAsync, null, 1000, RefreshIntervalMinutes * 60 * 1000);
}
public Task LoadingTask = Task.CompletedTask;
public Timer Timer { get; set; }
public long RefreshIntervalMinutes = 10;
public bool LoadingBusy = false;

private async void TimerTickAsync(object state)
{
if (LoadingBusy) return;
try
{
LoadingBusy = true;
LoadingTask = LoadCaches();
await LoadingTask;
}
catch
{
// do not crash the app
}
finally
{
LoadingBusy = false;
}
}
private async Task LoadCaches()
{
try
{
var places = await GetAllPlacesFromDb();
Cache.Set<AllPlacesResult>(CACHE_KEY_ALLPLACES, new AllPlacesResult() { Result = places, IsBusy = false });
}
catch{}
}
private async Task<List<SearchPlacesResultItem>> GetAllPlacesFromDb()
{
// blablabla
}

}

笔记:
DbContext选项需要注册为单例,默认选项现在已确定范围(我相信允许更简单的 Multi-Tenancy 配置)

services.AddDbContext<AppDbContext>(o =>
{
o.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
o.UseSqlServer(connectionString);
},
contextLifetime: ServiceLifetime.Scoped,
optionsLifetime: ServiceLifetime.Singleton);

关于caching - 在ASP.Net Core上具有自动重新生成的内存中缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44723017/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com