MemoryCache UpdateCallback не работи

Опитвам се да създам набор от връзки към API на трета страна и връзките да изтичат след определен интервал, ако не се използват. Когато изтекат, връзката им трябва да бъде прекъсната чрез API на трета страна.

Изглежда, че MemoryCache (System.Runtime.Caching) ще се справи с това. Изглежда обаче, че UpdateCallback се държи странно.

Прост пример за LINQPad:

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");
}

Ако стартирам това, резултатът е:

fig

Той НЕ извежда „стигам тук“.

Ако коментирам реда, който започва с policy.UpdateCallback, резултатът е:

null

какво правя грешно

Ако има по-добър начин да изпълня задачата си, отворен съм към алтернативни предложения.


person TrueWill    schedule 10.03.2012    source източник


Отговори (3)


Мисля, че проблемът може да е Thread.Sleep, защото това също блокира кеша, тъй като те работят в една и съща нишка. Ако се опитате да направите фиктивни цикли, ще видите, че манипулаторът за актуализиране е задействан:

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

Вместо сън.

person aweis    schedule 10.03.2012
comment
Вашият пример работи. Мога да получа тук, последвано от нула (което бих очаквал). Това изглежда странно - мислех, че изтичането на кеша ще настъпи в друга нишка. Благодаря! - person TrueWill; 11.03.2012

Просто добавете Console.ReadLine() в края на Main или заменете Sleep с Console.ReadLine(), стартирайте извадката си и изчакайте около 10 секунди. Ще получите очакваното съобщение. Таймерът в MemoryCache е малко бавен.

Но както и да е, със сигурност има грешка в MemoryCache: присвояването на UpdateCallback променя поведението, но не би трябвало.

В случай, че е зададен AbsoluteExpiration и времето е преминало, методът Get трябва да върне нула без зависимост от съществуването на UpdateCallback.

BTW, RemovedCallback не променя поведението.

person SergeyT    schedule 27.12.2012

Просто увеличете времето за заспиване до нещо много по-голямо и ще видите, че обратното извикване се изпълнява.

Изтичането се случва в друга нишка чрез таймер (можете да видите толкова, ако зададете точка на прекъсване в рамките на обратното извикване). Ето защо работи или сън, или изчакване при заетост.

person Ryan Burbidge    schedule 24.02.2014