We use the following template to handle universal object caching for our asp.net application.
private object SystemConfigurationCacheLock = new object(); public SystemConfiguration SystemConfiguration { get { if (HttpContext.Current.Cache["SystemConfiguration"] == null) lock (SystemConfigurationCacheLock) { if (HttpContext.Current.Cache["SystemConfiguration"] == null) HttpContext.Current.Cache.Insert("SystemConfiguration", GetSystemConfiguration(), null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration, new CacheItemUpdateCallback(SystemConfigurationCacheItemUpdateCallback)); } return HttpContext.Current.Cache["SystemConfiguration"] as SystemConfiguration; } } private void SystemConfigurationCacheItemUpdateCallback(string key, CacheItemUpdateReason reason, out object expensiveObject, out CacheDependency dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration) { dependency = null; absoluteExpiration = DateTime.Now.AddMinutes(1); slidingExpiration = Cache.NoSlidingExpiration; expensiveObject = GetSystemConfiguration(); } private SystemConfiguration GetSystemConfiguration() {
The problem is that upon loading (~ 100,000 users) we see a huge jump in TTFB, because CacheItemUpdateCallback blocks the execution of all other threads until it finishes updating the cache from the database.
So, it seems to me that we need a solution that when the first thread, after the cache expires, tries to access it, the asynchronous thread starts to update the cache, but still allows all other executable threads to read from the old cache until it successfully updated.
Is there anything built into the .NET platform that can handle what I ask, or will I have to write it from scratch? Your thoughts, please ...
Few things...
Using HttpContext.Current.Cache is random and optional, since we have no problem using private members in one element to store cached data.
Please do not comment on cache time, SPROC efficiency, why we cache in the first place, etc., since this is not relevant. Thanks!