You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MemoryCache条目过期时调用函数?及未更新键告警实现

实现方案

核心思路

要实现这个需求,需要结合缓存过期配置、定时更新校验和键状态跟踪三个核心环节:

  • 给缓存项设置120秒绝对过期时间,确保未被更新的项最终会自动失效
  • 维护一个待监控的键集合,每次更新时标记已处理的键,对比找出未更新的键触发告警
  • 每60秒执行一次更新+校验逻辑,形成闭环

具体实现步骤(以.NET MemoryCache 为例)

1. 初始化缓存与监控集合

用MemoryCache存储业务数据,同时用ConcurrentDictionary来跟踪所有需要监控的键(保证线程安全):

private readonly IMemoryCache _cache;
// 存储需要监控的键,值为最后更新时间戳
private readonly ConcurrentDictionary<string, DateTime> _monitoredKeys = new();

public CacheMonitorService(IMemoryCache cache)
{
    _cache = cache;
    // 初始化时可加载初始需要监控的键
    // _monitoredKeys.TryAdd("key1", DateTime.UtcNow);
}

2. 定义缓存项的过期策略

每次添加/更新缓存时,设置120秒的绝对过期时间,同时配置过期回调(双重保障,即使定时任务故障,过期时也能告警):

private void SetCacheItem(string key, object value)
{
    var cacheEntryOptions = new MemoryCacheEntryOptions()
        .SetAbsoluteExpiration(TimeSpan.FromSeconds(120))
        .RegisterPostEvictionCallback((evictedKey, _, reason, _) =>
        {
            // 若因过期被移除,触发告警
            if (reason == EvictionReason.Expired)
            {
                AlertAdmin($"缓存键 {evictedKey} 因未及时更新已过期");
            }
        });

    _cache.Set(key, value, cacheEntryOptions);
}

3. 定时更新与校验逻辑

每60秒执行一次任务,流程如下:

  • 获取本次要更新的键值对(比如从业务数据源拉取)
  • 遍历更新每个键的缓存值,并重置过期时间
  • 对比监控集合,找出未被本次更新覆盖的键,触发告警
  • 更新监控集合为本次的键列表
public async Task UpdateAndCheckCacheAsync()
{
    // 1. 获取本次需要更新的键值对(示例:从业务服务获取)
    var latestKeyValues = await GetLatestKeyValuesFromBusinessService();
    var updatedKeys = latestKeyValues.Select(kv => kv.Key).ToHashSet();

    // 2. 更新缓存并标记已更新
    foreach (var kv in latestKeyValues)
    {
        SetCacheItem(kv.Key, kv.Value);
        _monitoredKeys.TryUpdate(kv.Key, DateTime.UtcNow, _monitoredKeys.GetValueOrDefault(kv.Key));
    }

    // 3. 找出未被更新的键(监控集合中不在本次更新列表里的)
    var unupdatedKeys = _monitoredKeys.Keys.Except(updatedKeys).ToList();
    foreach (var key in unupdatedKeys)
    {
        AlertAdmin($"缓存键 {key} 未在本次周期内更新");
        // 从监控集合移除,避免重复告警(若后续恢复更新会重新加入)
        _monitoredKeys.TryRemove(key, out _);
    }

    // 4. 将本次新增的键加入监控集合
    foreach (var key in updatedKeys.Except(_monitoredKeys.Keys))
    {
        _monitoredKeys.TryAdd(key, DateTime.UtcNow);
    }
}

4. 告警函数实现

根据实际需求实现告警逻辑(比如邮件、企业微信、日志告警等):

private void AlertAdmin(string message)
{
    // 示例:写入告警日志,或调用通知接口
    Console.WriteLine($"【缓存告警】{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} - {message}");
    // 实际可替换为:SendEmailToAdmin(message); 或 SendWeChatAlert(message);
}

5. 配置定时任务

用IHostedService来每60秒触发一次UpdateAndCheckCacheAsync:

public class CacheUpdateBackgroundService : BackgroundService
{
    private readonly CacheMonitorService _cacheMonitor;
    private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(60);

    public CacheUpdateBackgroundService(CacheMonitorService cacheMonitor)
    {
        _cacheMonitor = cacheMonitor;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await _cacheMonitor.UpdateAndCheckCacheAsync();
            await Task.Delay(_updateInterval, stoppingToken);
        }
    }
}

关键注意事项

  • 线程安全:所有操作缓存和监控集合的地方必须保证线程安全,使用ConcurrentDictionary和MemoryCache的线程安全方法
  • 双重告警机制:定时校验+过期回调,避免因定时任务故障导致漏告警
  • 避免重复告警:未更新的键告警后从监控集合移除,后续恢复更新时重新加入

内容的提问来源于stack exchange,提问作者S.M_Emamian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:23:40