I have plenty of available ram (about 25 GB of free memory) and I don't want the cache to expire and I just remove and recache items when there is a change.As my website is in testing process it has 1 or 2 KBs of cached items but when I check cache after some time (like half an hour) I see that they have expired. I use this code for inserting into cache:
Cache.Insert(ckey, Results, null, Cache.NoAbsoluteExpiration, TimeSpan.Zero);
This is my first time to use cache, Does anybody know what is wrong with the code or the cache?
Chances are if you are leaving it for some time then your app domain is shutting down due to lack of use and if that goes so does its in memory cache.
ASP.NET Data Cache - preserve contents after app domain restart discusses this issue and some possible solutions to it.
try this
Cache.Insert(
ckey, Results,
null, /*CacheDependency*/
Cache.NoAbsoluteExpiration, /*absoluteExpiration*/
Cache.NoSlidingExpiration, /*slidingExpiratioin*/
CacheItemPriority.Normal, /*priority*/
null /*onRemoveCallback*/
);
View this article for further info, it may be already answered there:
Default duration of Cache.Insert in ASP.NET
I have stumbled upon a similar issue. It looks that HttpRuntime.Cache takes the liberty of removing items from cache when it "feels" that there is not enough memory. This happens even if CacheItemPriority.NotRemovable priority is provided along with no absolute/no sliding expiration and under normal application domain operation (no shutdown).
How to catch actual expiration
HttpRuntime.Cache provides a remove callback to be used when an item is removed. Of course, in order to filter out normal evictions on application pool shutdown, System.Web.Hosting.HostingEnvironment.ShutdownReason should be checked.
public class ApplicationPoolService : IApplicationPoolService
{
public bool IsShuttingDown()
{
return System.Web.Hosting.HostingEnvironment.ShutdownReason != ApplicationShutdownReason.None;
}
}
private void ReportRemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
if (!ApplicationPoolService.IsShuttingDown())
{
var str = $"Removed cached item with key {key} and count {(value as IDictionary)?.Count}, reason {reason}";
LoggingService.Log(LogLevel.Info, str);
}
}
HttpRuntime.Cache.Insert(CacheDictKey, dict, dependencies: null,
absoluteExpiration: DateTime.Now.AddMinutes(absoluteExpiration),
slidingExpiration: slidingExpiration <= 0 ? Cache.NoSlidingExpiration : TimeSpan.FromMinutes(slidingExpiration),
priority: CacheItemPriority.NotRemovable,
onRemoveCallback: ReportRemovedCallback);
Alternative
MemoryCache can be used as a good replacement for HttpRuntime.Cache. It provides very similar functionality. A full analysis can be read here.
Related
in Windows Azure Shared Cache:
suppose I do the following:
try
{
mCache.Remove(key);
Trace.WriteLine("removed successfully from Azure Shared Cache");
}
catch (DataCacheException e)
{
WorkerRole.log.Info(e.ToString());
}
is it right to say that if the code reached to the Trace.WriteLine command, then the operation completed successfully? (otherwise, it would be throwing DataCacheException.
I know I can register to the event CacheOperationCompleted, but is my code can be a good alternative to test operation success? (for Put/Remove methods).
thanks
Remove method returns boolean flag indicating whether an item identified by the given keyhas been removed (true) or not (false).
So if you want to check operation result I would suggest following approach:
if(mCache.Remove(key))
{
Trace.WriteLine("removed successfully from Azure Shared Cache");
}
As far as Put method is concerned, this might be a bit more complicated.
Basically, if your cache.Put(key, value) method completes successfully (no exceptions), you can assume your item has been added to your cache.
However, Azure cache items can be evicted from the cache (that depends on the cache size and item expiration time - default item expiration time is 48 hours for shared caching)
So in order to avoid any "surprises" I would recommend cache usage pattern as follows:
Get item from cache by a key
If cache return Null then create that item and put it into the cache
Perform operation on the item
Also as a side note, I would recommend using in-role caching instead of shared caching service (mostly because it is cheaper, has more features etc.).
I have the following problem, I have this kind of cache management:
public class CacheManager : ICacheManager {
private readonly ObjectCache cache;
public CacheManager() {
this.cache = MemoryCache.Default;
}
public void AddItem(string key, object itemToCache, double duration) {
var end = DateTime.Now.AddSeconds(duration);
this.cache.Add(key, itemToCache, end);
}
public T Get<T>(string key) where T : class {
try {
return (T)this.cache[key];
}
catch (Exception ex) {
return null;
}
}
public void Remove(string key) {
this.cache.Remove(key);
}
}
is quite simple.
Edit I (bug fixes in the text of the question)
Problem: When the cache for any key expires, all the following calls to get any object in cache return "null". I check the keys and are always correct.
The problem occurs only in the client's server in my PC and my server works perfectly.
thanks.
Edit II (advances)
When we restart the Application Pool in the customer's server, you problem is solved for a few hours.
There is a specific Application Pool for our site with the following settings:
Pipeline Manager mode: Integrated
Framework: v4.0
Enable 32-bit Application: True.
Other settings such as default.
On the server we have 2 sites, one with "Enable 32-bit Application" enabled, if both are disabled the error occurred, but do not know if this is the problem.
Edit III (advances)
As we fail to solve the problem, we decided to switch to Httpcontext.Current.Cache, and we could solve the problem. We wanted another solution and continue to use MemoryCache but did not result.
Resurrecting an old question, but I believe this problem is due to a bug that was only fixed in ASP.NET 4.5, but has a hotfix for earlier versions.
See this thread: MemoryCache Empty : Returns null after being set
Caching of this kind normally require your code to be in form "if an item is not in the cache then create the item, use the item that was created and also add to the cache, otherwise use the item from the cache". So normally it should be a problem if an item is not in the cache.
Common reason for items to disappear from the cache is high memory usage. In this case memory cache may immediately evict items as soon as they added to cache. This behavior is very common for applications running in 32 bit (x86), sepecially on servers handling a lot of requests or large amount of data.
To verify - collect memory conuters and process' bitness. Consider adding code to listen for removal of items from the cache by using MemoryCache.CreateCacheEntryChangeMonitor and corresponding events.
We're using the following pattern to handle caching of universal objects 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()
{
//Load system configuration
}
The problem is that when under load (~100,000 users) we see a huge jump in TTFB as the CacheItemUpdateCallback blocks all the other threads from executing until it has finished refreshing the cache from the database.
So what I figured we needed is solution that when the first thread after an expiry of the cache attempts to access it, an asynchronous thread is fired off to update the cache but still allows all other executing threads to read from the old cache until it has sucessfully updated.
Is there anything built into the .NET framework that can natively handle what I'm asking, or will I have to write it from scratch? Your thoughts please...
A couple of things...
The use of the HttpContext.Current.Cache is incidental and not necessarily essential as we've got no problem using private members on a singleton to hold the cached data.
Please don't comment on the cache times, SPROC effeciency, why we're caching in the first place etc as it's not relevent. Thanks!
AppFabric might be a good fit for what you're looking for.
http://msdn.microsoft.com/en-us/windowsserver/ee695849
http://msdn.microsoft.com/en-us/library/ff383731.aspx
So it turns out after several hours of investigation that the problem is not the CacheItemUpdateCallback blocking other threads as I originally thought, in fact it did exactly what I wanted it to asynchronously but it was the garbage collector stopping everything to clean up the LOH.
i have the following code to cache some expensive code.
private MyViewModel GetVM(Params myParams)
{
string cacheKey = myParams.runDate.ToString();
var cacheResults = HttpContext.Cache[cacheKey] as MyViewModel ;
if (cacheResults == null)
{
cacheResults = RunExpensiveCodeToGenerateVM(myParams);
HttpContext.Cache[cacheKey] = cacheResults;
}
return cacheResults;
}
will this stay in the cache forever? until the server reboots or runs out of memory?
will this stay in the cache forever?
This will depend on the particular cache provider you are using. For example if you are using the default in-memory cache it might expire if the server starts running low on memory or if the application pool is recycled. But if you are using some other cache provider, like for example a distributed cache like memcached or AppFactory this will depend on the particular implementation.
The rule of thumb is to never assume that something is inside the cache because you previously stored it. Always check for the presence of the item in the cache first and if not present fetch it and store in the cache again.
THis is an interesting question. I am developing a web-chat software piece and for the past couple of hours I've been trying to figure out why this happens. Basically, I add an actual chat object (the part that does communications) to the Cache collection when you start chatting. In order to detect that you closed the window, I set the sliding expiration to say 10-30 seconds. I also set the callback to let the chat client know that he needs to disconnect to end the chat session. For some odd reason, when I use the code to dispose of the chat client, whatever it is, it causes the entire w3svc process to crash (event log checked). I also tried just sending myself an email when the item is removed, which worked. I even tried to put the entire code in try-catch block but it seems to ignore that as well. Any ideas? O_o
UPD: No, i am not trying to refresh the object (in reference to this).
Adding:
HttpContext.Current.Cache.Insert("ChatClient_" + targetCid + HttpContext.Current.Session.SessionID, cl, null, Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(15), CacheItemPriority.Normal, new CacheItemRemovedCallback(removeMyself));
Removing:
public static void removeMyself(string key, Object value, CacheItemRemovedReason reason) {
var wc = (WebClient)value;
try {
wc.Remove();
}
catch { }
}
I am in fact using the lock on HttpContext.Current.cache when adding to the cache objects.
Can you post both the cache.insert and item removed callbacks code? Are you using any kind of locking when inserting into the cache? Have you done anything to the default settings for the ASP.net cache? Are you able to reproduce this on another web server? Are you sure you are expiring the cache in ms instead of seconds...
Is your sliding expiration like this? TimeSpan.FromSeconds(30)