2

I have implemented a cache that renews the containing values when they expire.

My code is this:

class MyCache
{
    private static readonly MemoryCache Cache = MemoryCache.Default;

    private CacheItemPolicy _errorpolicy;
    private CacheItemPolicy _warnPolicy;

    private CacheEntryRemovedCallback _warnCacheEntryRemovedCallback;
    private CacheEntryRemovedCallback _errorCacheEntryRemovedCallback;

    public void AddErrors(string key, object errors)
    {
        _errorCacheEntryRemovedCallback = ErrorItemRemovedCallback;
        _errorpolicy = new CacheItemPolicy
        {
            AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(7.00),
            RemovedCallback = _errorCacheEntryRemovedCallback
        };

        Cache.Set(key, errors, _errorpolicy);
    }

    public void AddWarnings(string key, object warnings)
    {
        _warnCacheEntryRemovedCallback = WarningCacheItemRemovedCallback;
        _warnPolicy = new CacheItemPolicy
        {
            AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(4.00),
            RemovedCallback = _warnCacheEntryRemovedCallback
        };

        Cache.Set(key, warnings, _warnPolicy);
    }

    private void ErrorItemRemovedCallback(CacheEntryRemovedArguments arguments)
    {
        Console.WriteLine("{0} Item removed: {1}", DateTime.UtcNow, arguments.CacheItem.Key);
        Cache.Set(arguments.CacheItem.Key, new List<string> { "error1", "error2", "error3" }, _errorpolicy);

    }

    private void WarningCacheItemRemovedCallback(CacheEntryRemovedArguments arguments)
    {
        Console.WriteLine("{0} Item removed: {1}", DateTime.UtcNow, arguments.CacheItem.Key);
        Cache.Set(arguments.CacheItem.Key, new List<string> { "warn1", "warn2", "warn3" }, _warnPolicy);
    }
}

But something is wrong.

The above writes this in the prompt:

04-05-2014 21:20:00 Item removed: warn
04-05-2014 21:20:00 Item removed: error
04-05-2014 21:20:20 Item removed: error
04-05-2014 21:20:20 Item removed: warn
04-05-2014 21:20:40 Item removed: warn
04-05-2014 21:20:40 Item removed: error
04-05-2014 21:20:40 Item removed: error
04-05-2014 21:20:40 Item removed: warn

... and I would have expected somnething like

04-05-2014 21:20:04 Item removed: warn
04-05-2014 21:20:07 Item removed: error
04-05-2014 21:20:08 Item removed: warn
04-05-2014 21:20:12 Item removed: warn
04-05-2014 21:20:14 Item removed: error
...

What am I missing?

Update 2014-05-14:

I have changed the field-level variables to local variables - but the same behaviour exists. Notice also that the sequence of removal from cache alters - first it is "errors-then-warns" - but next time it is "warns-then-errors".

Also notice that the first removal from cache is after 21 seconds - after this it happens constantly every 20 seconds.

14-05-2014 13:00:59 Adding errors to cache
14-05-2014 13:00:59 Adding warnings to cache
Press 'q' to quit
14-05-2014 13:01:20 Item removed: warn
14-05-2014 13:01:20 Item removed: error
14-05-2014 13:01:40 Item removed: error
14-05-2014 13:01:40 Item removed: warn
14-05-2014 13:02:00 Item removed: warn
14-05-2014 13:02:00 Item removed: error
14-05-2014 13:02:20 Item removed: error
14-05-2014 13:02:20 Item removed: warn
14-05-2014 13:02:40 Item removed: warn
14-05-2014 13:02:40 Item removed: error

My entire (new code) is here:

namespace DemoCache
{
    internal class Program
    {
        private static readonly List<string> ErrorList = new List<string> {"error1", "error2", "error3"};
        private static readonly List<string> WarningList = new List<string> {"warn1", "warn2", "warn3"};

        static void Main()
        {
            var myCache = new MyCache();

            Console.WriteLine("{0} Adding errors to cache ", DateTime.UtcNow);
            myCache.AddErrors("error", ErrorList);
            Console.WriteLine("{0} Adding warnings to cache", DateTime.UtcNow);
            myCache.AddWarnings("warn", WarningList);

            Console.WriteLine("Press 'q' to quit");

            var keepRunning = true;
            do
            {
                var key = Console.ReadKey(true);

                switch (Char.ToLower(key.KeyChar))
                {
                    case 'q':
                        keepRunning = false;
                        break;
                }
            } while (keepRunning);
        }
    }

    class MyCache
    {
        private static readonly MemoryCache Cache = new MemoryCache("name");

        //private CacheItemPolicy _errorpolicy;
        //private CacheItemPolicy _warnPolicy;

        //private CacheEntryRemovedCallback _warnCacheEntryRemovedCallback;
        //private CacheEntryRemovedCallback _errorCacheEntryRemovedCallback;

        public void AddErrors(string key, object errors)
        {
            CacheEntryRemovedCallback errorCacheEntryRemovedCallback = ErrorItemRemovedCallback;
            var errorpolicy = new CacheItemPolicy
            {
                AbsoluteExpiration = DateTime.Now.AddSeconds(7.00),
                RemovedCallback = errorCacheEntryRemovedCallback
            };

            Cache.Set(key, errors, errorpolicy);
        }

        public void AddWarnings(string key, object warnings)
        {
            CacheEntryRemovedCallback warnCacheEntryRemovedCallback = WarningCacheItemRemovedCallback;
            var warnPolicy = new CacheItemPolicy
            {
                AbsoluteExpiration = DateTime.Now.AddSeconds(11.00),
                RemovedCallback = warnCacheEntryRemovedCallback
            };

            Cache.Set(key, warnings, warnPolicy);
        }

        private void ErrorItemRemovedCallback(CacheEntryRemovedArguments arguments)
        {
            Console.WriteLine("{0} Item removed: {1}", DateTime.UtcNow, arguments.CacheItem.Key);
            AddErrors(arguments.CacheItem.Key, new List<string> { "error1", "error2", "error3" });
            //Cache.Set(arguments.CacheItem.Key, , _errorpolicy);

        }

        private void WarningCacheItemRemovedCallback(CacheEntryRemovedArguments arguments)
        {
            Console.WriteLine("{0} Item removed: {1}", DateTime.UtcNow, arguments.CacheItem.Key);
            AddWarnings(arguments.CacheItem.Key, new List<string> { "warn1", "warn2", "warn3" });
            //Cache.Set(arguments.CacheItem.Key, new List<string> { "warn1", "warn2", "warn3" }, _warnPolicy);
        }
    }
}
4
  • Start by removing the field level variables which you reset the reference instance of per call. Take all fields that start with _ and move them to method-level arguments, then see if the problem persists. Commented May 5, 2014 at 13:43
  • @DavidHaney I tried what you suggested - same behaviour :-( . I have updated the original post to list current code. Commented May 14, 2014 at 13:05
  • @DavidHaney Hey, just for the fun of it, I tried to change AddSeconds() to AddMinutes(), and now the behaviour is exactly as I would expect it. Is there some sort of minimum timespan to use (more than a few seconds) to have intended behaviour? Commented May 14, 2014 at 21:43
  • Good question. I bet there probably is. Try adding a large number of seconds, like 1000? Commented May 14, 2014 at 21:52

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.