如何从消费端触发FusionCache的EagerRefresh主动刷新机制?
FusionCache EagerRefresh 触发方案(生产者-消费者场景)
针对你的场景——只有生产者服务能生成数据,需在缓存值进入宽限期时触发EagerRefresh,而消费者仍正常读取缓存(含宽限期旧值),以下是可行的解决方案:
方案1:直接读取FusionCache内置元数据
FusionCache会自动为每个缓存项存储元数据(过期时间、宽限期结束时间等),你无需解析内存/Redis的原始存储,直接通过GetMetadataAsync<T>方法获取:
// 生产者服务中的逻辑 var metadata = await _fusionCache.GetMetadataAsync<YourDataType>(cacheKey); if (metadata != null) { var now = DateTimeOffset.UtcNow; // 判断是否处于宽限期:当前时间 >= 缓存过期时间,且 < 过期时间+宽限期的绝对截止时间 var isInGracePeriod = now >= metadata.ExpiresAt && now < metadata.AbsoluteExpiration; if (isInGracePeriod) { // 主动触发刷新:跳过现有缓存,直接生成新数据并更新缓存 await _fusionCache.GetOrSetAsync(cacheKey, async () => await ProduceNewData(), options => options .SetDuration(TimeSpan.FromHours(1)) // 正常缓存时长 .SetGracePeriod(TimeSpan.FromMinutes(10)) // 宽限期配置 .SetEagerRefresh(true) .SkipCache(true) // 强制绕过缓存,生成新值覆盖 ); } }
注意事项
GetMetadataAsync优先从本地内存缓存读取元数据,内存未命中时再从Redis背板获取,适配你的分布式缓存场景。SkipCache(true)确保本次调用不会复用旧缓存值,直接生成最新数据并更新缓存。
方案2:调整EagerRefresh触发阈值,利用内置逻辑
FusionCache的EagerRefresh默认会在缓存剩余有效期低于阈值时,由第一个访问请求触发刷新。你可以让生产者定期调用缓存检查,配合调整触发阈值实现需求:
// 生产者的缓存配置 var cacheOptions = new FusionCacheEntryOptions() .SetDuration(TimeSpan.FromHours(1)) .SetGracePeriod(TimeSpan.FromMinutes(10)) .SetEagerRefresh(true) // 设置触发阈值:缓存剩余有效期小于15分钟时,触发EagerRefresh .SetEagerRefreshTriggerThreshold(TimeSpan.FromMinutes(15)); // 生产者通过定时任务(如Hangfire、HostedService)定期调用,触发刷新检查 await _fusionCache.TryGetAsync<YourDataType>(cacheKey, cacheOptions);
方案3:自定义元数据存储(备选)
若不想依赖FusionCache内置元数据,可在存储缓存时额外保存自定义元数据(单独Redis键或与数据序列化在一起):
// 存储数据时同步保存元数据 var data = await ProduceNewData(); var customMetadata = new CacheMetadata { ExpiresAt = DateTimeOffset.UtcNow.AddHours(1), GracePeriodEndsAt = DateTimeOffset.UtcNow.AddHours(1).AddMinutes(10) }; // 存储主数据到FusionCache await _fusionCache.SetAsync(cacheKey, data, options => options .SetDuration(TimeSpan.FromHours(1)) .SetGracePeriod(TimeSpan.FromMinutes(10)) ); // 存储自定义元数据到Redis(单独键) await _redisConnection.GetDatabase().StringSetAsync($"{cacheKey}:metadata", JsonSerializer.Serialize(customMetadata));
然后在生产者中读取判断:
var metadataJson = await _redisConnection.GetDatabase().StringGetAsync($"{cacheKey}:metadata"); if (!metadataJson.IsNullOrEmpty) { var customMetadata = JsonSerializer.Deserialize<CacheMetadata>(metadataJson); var now = DateTimeOffset.UtcNow; if (now >= customMetadata.ExpiresAt && now < customMetadata.GracePeriodEndsAt) { await RefreshCache(cacheKey); // 调用刷新逻辑 } } // 刷新逻辑实现 async Task RefreshCache(string key) { var newData = await ProduceNewData(); await _fusionCache.SetAsync(key, newData, options => options .SetDuration(TimeSpan.FromHours(1)) .SetGracePeriod(TimeSpan.FromMinutes(10)) .SetEagerRefresh(true) ); }
内容的提问来源于stack exchange,提问作者ZorgoZ
相关产品推荐
相关产品推荐

