feat:优化日历缓存,采用ConditionalWeakTable。

This commit is contained in:
ruisu
2026-08-05 16:35:40 +08:00
parent 8fb3c4392c
commit c771496ecd
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using YLErp.BLL;
namespace YLErp.Modules.RiskEngine
@@ -13,6 +14,12 @@ namespace YLErp.Modules.RiskEngine
/// </summary>
public static class RiskCalendarHelper
{
/// <summary>
/// 按当前风控执行使用的数据库上下文保存日历缓存,同一次风控检查内复用,数据库上下文释放后不阻止缓存被回收。
/// </summary>
private static readonly ConditionalWeakTable<YLContext, Dictionary<string, HashSet<string>>> HolidayCaches =
new ConditionalWeakTable<YLContext, Dictionary<string, HashSet<string>>>();
/// <summary>
/// 获取指定日期的上一银行间交易日。
/// </summary>
@@ -36,7 +43,8 @@ namespace YLErp.Modules.RiskEngine
if (dbContext == null)
throw new ArgumentNullException(nameof(dbContext));
var holidayCache = new Dictionary<int, HashSet<string>>();
// 以本次风控检查的数据库上下文为缓存边界,避免不同规则重复读取和解析相同市场日历。
var holidayCache = HolidayCaches.GetOrCreateValue(dbContext);
var currentDate = date.Date.AddDays(-1);
// 最多向前查 370 天,既覆盖跨年和长假场景,也避免日历配置异常时出现无限循环。
@@ -60,11 +68,13 @@ namespace YLErp.Modules.RiskEngine
/// </summary>
/// <param name="dbContext">当前风控执行使用的数据库上下文。</param>
/// <param name="year">日历年份。</param>
/// <param name="holidayCache">单次查询过程内的年份级缓存,跨年查找时避免重复读取同一年日历。</param>
/// <param name="holidayCache">单次风控检查内按市场和年份共享的非交易日缓存。</param>
/// <returns>格式为 yyyy,MM,dd 的非交易日集合。</returns>
private static HashSet<string> GetHolidays(YLContext dbContext, int year, string country, string calendarName, Dictionary<int, HashSet<string>> holidayCache)
private static HashSet<string> GetHolidays(YLContext dbContext, int year, string country, string calendarName, Dictionary<string, HashSet<string>> holidayCache)
{
if (holidayCache.TryGetValue(year, out var holidays))
// 缓存需要同时区分市场和年份,避免银行间与交易所同一年日历相互串用。
var cacheKey = $"{country.ToUpperInvariant()}:{year}";
if (holidayCache.TryGetValue(cacheKey, out var holidays))
return holidays;
// 同一年可能存在多种市场日历,按规则对应的市场代码读取非交易日。
@@ -90,7 +100,7 @@ namespace YLErp.Modules.RiskEngine
}
holidays = new HashSet<string>(holidayList ?? new List<string>());
holidayCache[year] = holidays;
holidayCache[cacheKey] = holidays;
return holidays;
}
}