MemoryCache expired callback

MemoryCache 有一個好用但比較少去碰觸的功能,那就是當你的 cache 過期時,怎麼透過事件來通知你做後續的處理

cache expired 需要透過事件通知在實際生活上有很多應用情境,比如即時刷新最新比賽記錄,暫存只設定 30 秒,當超過這個時間就會自動把最新結果廣播給所有用戶

但今天我的情境是將 cache 當成一個批次處理的概念,也就是我希望在 5 分鐘內蒐集資訊,當超過 5 分鐘的快取時間後,我就將這個批次拿到的所有資料寫到 db

MemoryCache 裡的 CacheItemPolicy 有提供了一個 RemovedCallback 的事件函式,可以很方便的讓你去處理當 cache key expired 時要怎麼處理

使用方式也非常簡單,以下例子為傳入 key 跟 欲設定的過期秒數,若過期的話希望執行什麼樣的 callback 函式

       static ObjectCache _cache = MemoryCache.Default;
       public static void Set(string key, int expiredSeconds)
       {
           var policy = new CacheItemPolicy();
           var cacheTime = new TimeSpan(0, 0, expiredSeconds);
           policy.AbsoluteExpiration = DateTimeOffset.Now.Add(cacheTime);
           policy.RemovedCallback = new CacheEntryRemovedCallback(OnExpire);
           _cache.Set(key, key + "_value", policy);
       }
 
       public static void OnExpire(CacheEntryRemovedArguments cacheEntryRemovedArguments)
       {
           //process in db
           var expired_value = cacheEntryRemovedArguments.CacheItem.Value;
           Console.WriteLine($"Key [{cacheEntryRemovedArguments.CacheItem.Key}] Expired. Reason: {cacheEntryRemovedArguments.RemovedReason.ToString()} {DateTime.Now.ToString("HH:mm:ss")}");
       }


主函式的互動部份則是讓操作者輸入 cache key 的值,以及要過期的秒數,並加以觀察過期後的事件輸出

      static void Main(string[] args)
       {
           while (true)
           {
               Console.WriteLine($"input key");
               var key = Console.ReadLine();
               
               if (key == "")
                   break;
               var isExist = _cache.Contains(key);
               if (isExist)
               {
                   Console.WriteLine($"Get from cache: {_cache[key].ToString()} {DateTime.Now.ToString("HH:mm:ss")}");
               }
               else
               {
                   Console.WriteLine("input time(secs) to be expired");
                   var expiredTime = int.Parse(Console.ReadLine());
                   Set(key, expiredTime);
                   Console.WriteLine($"cache set done {DateTime.Now.ToString("HH:mm:ss")}");
               }
           }
       }

測試

 

 

 

 

 

 

 

 

 

在 16:30:02 建立了 cache,並設定於 10 秒後過期,所以理當會在 16:30:12 過期

17:30:02 正常取到值
17:30:04 正常取到值
17:30:05 正常取到值
17:30:06 正常取到值
17:30:07 正常取到值
*17:30:12 過期
17:30:20 自動觸發 expired callback 事件

在 callback 的執行上是以 10 秒為一週期,如果在 16:20:12 過期之後沒有取值的任何動作,則 callback 的執行會在 16:20:20 這個時間點才會被執行

於此,我們可以再做另一個實驗證實這一點

 

 

 

 

 

 

 

 

 

17:38:33 建立 cache, 10 秒後過期,將於 17:38:43 過期,在上面的例子,如果不做取值的任何動作,將會在 17:38:50 回收時才會觸發事件
17:38:34 正常取到值
17:38:35 正常取到值
17:38:37 正常取到值
17:38:42 正常取到值
*17:38:43 過期
17:38:44 取值後發現 cache 已過期,觸發 expired callback 事件

 

參考來源

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.caching.cacheitempolicy.removedcallback?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0#System_Runtime_Caching_CacheItemPolicy_RemovedCallback

https://docs.microsoft.com/en-us/dotnet/api/system.web.caching.cacheitemremovedcallback?view=netframework-4.8