.NET Core 2.0中IMemoryCache未按预期缓存至下周一,仅维持1小时的问题
问题分析与解决方案
嘿,咱们先把你的核心疑问解决掉:这个问题和Token有效期完全没关系!你缓存的是GetRanking的查询结果数据,和Token(不管是JWT还是数据库连接Token)的有效期没有直接关联——如果是Token过期导致的问题,你应该会收到数据库连接或授权错误,而不是成功重新从数据库拉取数据。
接下来咱们看真正的问题所在,以及怎么修复:
一、缓存失效的可能原因
你的代码逻辑看起来是想让缓存维持到下周一,但实际只撑1小时,大概率是以下两种情况:
- 进程内缓存的局限性
IMemoryCache是进程内缓存,一旦你的.NET Core应用程序重启(比如服务器应用池设置了1小时自动回收、代码部署更新、内存不足触发进程重启),缓存就会被清空,不得不重新从数据库拉取数据。 - 缓存过期时间的设置逻辑有瑕疵
你当前用TimeSpan.FromDays(diff)设置相对过期时间,但这种方式是从当前时间往后推N天,而不是固定到下周一的零点。另外,当计算diff时,周日的情况会出现逻辑偏差(比如周日时daysToStartWeek = DayOfWeek.Sunday - DayOfWeek.Monday = -1,diff会算出1,导致缓存只维持1天)。
二、修正后的代码方案
要实现「每周一自动更新缓存」的需求,更可靠的方式是设置绝对过期时间(固定到下周一的零点),同时优化缓存项的优先级,避免内存不足时被提前回收。修改后的代码如下:
var dateNow = DateTime.Now; DateTime nextMonday; if (dateNow.DayOfWeek == DayOfWeek.Monday) { // 今天是周一,缓存到下周一的零点 nextMonday = dateNow.AddDays(7).Date; } else { // 计算距离下周一的天数,逻辑更简洁准确 int daysUntilMonday = ((int)DayOfWeek.Monday - (int)dateNow.DayOfWeek + 7) % 7; nextMonday = dateNow.AddDays(daysUntilMonday).Date; } // 先尝试从缓存获取 if (_cache.TryGetValue("GetRanking", out IEnumerable<GetRankingStruct> objRanking)) { return Ok(objRanking); } // 缓存未命中,从数据库拉取 var dp = new DataProvider(Configuration); var response = dp.GetRanking(userName, asAtDate); // 设置缓存:绝对过期到下周一零点,高优先级防止被提前回收 _cache.Set("GetRanking", response, new MemoryCacheEntryOptions { AbsoluteExpiration = nextMonday, Priority = CacheItemPriority.High }); return Ok(response);
三、额外排查建议
如果修改后还是出现1小时缓存失效的情况,你需要检查:
- 服务器的应用池设置:是否开启了1小时自动回收?如果是,要么调整回收时间,要么改用分布式缓存(比如Redis)来避免进程重启丢失缓存。
- 其他代码逻辑:有没有其他地方调用了
_cache.Remove("GetRanking")或者更新了这个缓存键? - 内存压力:服务器是否内存不足?
IMemoryCache会在内存紧张时自动回收低优先级的缓存项,所以我们设置了Priority = CacheItemPriority.High来降低这种风险。
内容的提问来源于stack exchange,提问作者Aless Hosry




