Issue using HttpRuntime.Cache

13,920

Solution 1

When you say every two minutes the value inserted is set to null, does that mean just the item you're interested in or every single item in the cache?

I ask this because the cache only exists as long as the application is running. If the application is restarted, the cache goes away. This would explain the behavior if everything goes away every 2 minutes. In that case you have a different problem on your hands: why does the application restart every 2 minutes.

If it's only SOME items then it could be a memory issue. The cache cleans itself up in response to low memory. I believe there's a way to set priority on values inserted. But this should only be a problem when you're low on memory.

If this still doesn't solve your problem, there is a way to discover why an item is being removed. It is explained here.

Solution 2

Well first of all your access isn't synchronized so that's a great source of problems. Reading from the HttpRuntime Cache is guarantied to be thread safe so you should really try reading your item as your first step on each and every cache operation.

Between checking if Exists and actually retrieving the item lots of things can happen (such as your item not beeing there anymore). You should get a handle of the item you're looking for, and if it isn't there provide thread-safe insert by fetching it from your persistent data store.

So your Add logic would get inside your Get IF the data isn't there. There's nothing fundamentally wrong in providing separate Add logic and you should measure the cost of hitting the database multiple times compared to blocking further requests for that specific piece of data.

T GetT(string key)
{
    T item = (cache.Get(key) as T);
    if (item == null)
    {
        lock (yourSyncRoot)
        {
            // double check it here
            item = (cache.Get(key) as T);
            if (item != null)
                return item;

            item = GetMyItemFromMyPersistentStore(key); // db?
            if (item == null)
                return null;

            string[] dependencyKeys = {your, dependency, keys};

            cache.Insert(key, item, new CacheDependency(null, dependencyKeys), 
                         absoluteExpiration, slidingExpiration, priority, null);
        }
    }
    return item;
}

Depending on your expiration policy you'll get your data in memory and provide fast & synchronized access to it, but as I said, measure it and adjust it to your needs. In your business logic after updating your item and properly saving it to your persistent store, just remove it from cache and the next call to your Get will fetch it again.

Solution 3

It could be because memory is running low, the cache will automatically kill off items in the cache when memory is becoming scarce, There is an optional parameter to set the priority of items in the cache if you want one item to be cleared before another.

Share:
13,920
user74042
Author by

user74042

Updated on July 13, 2022

Comments

  • user74042
    user74042 almost 2 years

    Am using following .net code to add objects to cache:

    public static void Add<T>(string key, T dataToCache)
    {
        try
        {
            ApplicationLog.Instance.WriteInfoFormat("Inserting item with key {0} into Cache...", key);
    
            HttpRuntime.Cache.Insert(
                key,
                dataToCache,
                null,
                DateTime.Now.AddDays(7),
                System.Web.Caching.Cache.NoSlidingExpiration);
        }
    
        catch (Exception ex)
        {
            ApplicationLog.Instance.WriteException(ex);             
        }
    }
    

    and here is my code to retrieve values from cache:

    public static T Get<T>(string key) 
    {   
        try
        {                
            if (Exists(key))
            {
                ApplicationLog.Instance.WriteInfoFormat("Retrieving item with key {0} from Cache...", key);
    
                return (T)HttpRuntime.Cache[key];
            }
            else
            {
                ApplicationLog.Instance.WriteInfoFormat("Item with key {0} does not exist in Cache.", key);
                return default(T); 
            }
        }
        catch(Exception ex)
        {
            ApplicationLog.Instance.WriteException(ex);
            return default(T); 
        }
    }
    
    
    public static bool Exists(string key)
    {
        bool retVal = false;
        try
        {
            retVal= HttpRuntime.Cache[key] != null;
        }
        catch (Exception ex)
        {
            ApplicationLog.Instance.WriteException(ex);
        }
        return retVal; 
    }
    

    But i find that after every 2 minutes or so,the cached object value is getting set to null resulting in pulling that value from database again.

    What am i missing here?

    • nuiun
      nuiun almost 15 years
      I think the code that would be utilizing your cache would be more relevant. For example, are you adding the same key to the cache multiple times?
    • colithium
      colithium almost 15 years
      Because he's using insert, that will just update the item if it's already in the cache.
    • Richard Anthony Freeman-Hein
      Richard Anthony Freeman-Hein almost 15 years
      Is your ASP.NET configuration the default settings? For instance, is the ASP.NET set to recycle for some reason, after a certain amount of memory is allocated, or time has passed? How about your application pool settings? Basically, are you sure that the HttpRuntime isn't being restarted?
    • Dunc
      Dunc almost 9 years
      Note that a potential race condition exists in your Get() method, since the cache could be updated between the Exists() call and HttpRuntime.Cache[key]. See last point here: stackoverflow.com/a/11432864/188926
  • user74042
    user74042 almost 15 years
    thanks for ur input...yes, the value is set to null for every item in the cache..
  • colithium
    colithium almost 15 years
    Can you check the logs to confirm if the app is restarting and if so why? Once you find that out you should be able to solve it or post another question.
  • Andrew Theken
    Andrew Theken over 13 years
    this could be improved a touch my adding a lambda to the Get and making it an extension method... static T Get<T>(this Cache cache, String key, Func<T> retrieveFunc);
  • Keith Robertson
    Keith Robertson almost 12 years
    @eych, "Cache access is thread-safe" means that a single operation on the object behaves atomically and won't cause failures when hit by multiple threads. However, multiple operations on the object still need to be syncronized by locks, even for thread-safe collections. Here we have a "Get" and an "Insert" if the get didn't find an object. This pair must be locked or else two or more different threads could pass the "Get", not find an object, and the create and "Insert" it. If we want only one thread to create and insert the object, then the operation pair must be locked. Common pattern.