Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MemoryCache UpdateCallback not working

I'm trying to create a pool of connections to a third-party API, and have connections expire after an interval if they are not in use. When they expire, they need to be disconnected via the third-party API.

It appeared that MemoryCache (System.Runtime.Caching) would handle this. UpdateCallback seems to behave oddly, though.

A simple LINQPad example:

void Main()
{
    var cache = MemoryCache.Default;
    var policy = new CacheItemPolicy();
    policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(1);
    policy.UpdateCallback = Update;
    cache.Set("figkey", "fig", policy);

    Thread.Sleep(2000);

    object result = cache.Get("figkey");

    Console.WriteLine(result == null ? "null" : result);
}

public static void Update(CacheEntryUpdateArguments arguments)
{
    Console.WriteLine("got here");
}

If I run this, the output is:

fig

It does NOT output "got here".

If I comment out the line that starts with policy.UpdateCallback, the output is:

null

What am I doing wrong?

If there's a better way to accomplish my task, I'm open to alternative suggestions.

like image 433
TrueWill Avatar asked Mar 10 '12 22:03

TrueWill


2 Answers

I Think that the problem may be the Thread.Sleep because that also blocks the cache, as they run in the same thread. If you try to make dummy loops you will se that the update handler is triggered:

var i = 0;
for (var j = 0; j < 10000000; j++)
{
    for (var k = 0; k < 1000000; k++)
        i++;
    i--;
}
Console.WriteLine(i);

Instead of the sleep.

like image 99
aweis Avatar answered Oct 28 '22 00:10

aweis


Just add Console.ReadLine() at the end of Main or replace Sleep with Console.ReadLine(), start your sample and wait about 10 seconds. You'll get the expected message. The timer inside MemoryCache is a bit slow.

But anyway, there certainly is a bug in MemoryCache: assigning UpdateCallback changes the behaviour, but it shouldn't.

In case if AbsoluteExpiration is set and the time is passed the method Get must return null without a dependency on existence of UpdateCallback.

BTW, RemovedCallback doesn't change the behavior.

like image 1
SergeyT Avatar answered Oct 27 '22 22:10

SergeyT