Sunday 19 May 2019

Be careful with MemoryCache

Imagine a .NET code block like below:


var memCache = new System.Runtime.Caching.MemoryCache("Cache1");
            memCache.Add("Key1", "Val1", new CacheItemPolicy() { AbsoluteExpiration = DateTime.UtcNow.AddDays(1) });
            Console.WriteLine(memCache["Key1"]);
            var memCache2 = new System.Runtime.Caching.MemoryCache("Cache1");
            Console.WriteLine(memCache2["Key1"]);
            Console.WriteLine(memCache["Key1"]);

What do you expect in output?

Well, as opposed to what some might expect, 2 line printed on console is null.

In fact, if you extend the code to like below, you will come to realize that everytime you new up a MemoryCache instance; even if it is with same name within same process, it is a different one.

var memCache = new System.Runtime.Caching.MemoryCache("Cache1");

            memCache.Add("Key1", "Val1", new CacheItemPolicy() { AbsoluteExpiration = DateTime.UtcNow.AddDays(1) });
            Console.WriteLine(memCache["Key1"]);
            var memCache2 = new System.Runtime.Caching.MemoryCache("Cache1");
            Console.WriteLine(memCache2["Key1"]);
            Console.WriteLine(memCache["Key1"]);
            memCache2.Add("Key1", "Val2", new CacheItemPolicy() { AbsoluteExpiration = DateTime.UtcNow.AddDays(1) });
            Console.WriteLine(memCache2["Key1"]);
            Console.WriteLine(memCache["Key1"]);
            Console.ReadLine();


Keep this in mind and save yourself from some weird performance issues :).

Tuesday 7 May 2019

Where is the bug, bro?

I was recently ran into an interesting issue when using JsonConvert.DeserializeObject method within Parallel.ForEach function. 

Here is the code:


public class Temp
{
   public int A { get; set; }

   public string B { get; set; }
}


static async Task Main(string[] args)
{
    var counter = 0;
    Temp t = new Temp();
    var str = JsonConvert.SerializeObject(t);
    while (counter <= 25)
    {
       var itemsInList = new List<string>();
for (int i = 0; i < 10; i++)
       {
              itemsInList.Add(str);
}

var tempList = new List();
       Parallel.ForEach(itemsInList, (item) =>
       {
              var y = JsonConvert.DeserializeObject(item);
              tempList.Add(y);
});

       foreach (var tempItem in tempList)
       {
Console.WriteLine("A  :" + tempItem.A);
}
Console.Read();
       counter++;
    }
}


If we run this a few times, you will run into an odd "Object reference not set to an instance of an object" error.


Now that is odd as that is intermittent and that indicated that the issue was with Deserialization code. Well, it is not the case.

If you replace the Parallel.ForEach block with following, you will notice that the new logic is never run.

Parallel.ForEach(itemsInList, (item) =>
{
var y = JsonConvert.DeserializeObject(item);
       if(y == null)
       {
              Console.WriteLine("Some issue with deserialization");
}
tempList.Add(y);
});


Mystery deepens ??

Well, not really. As an experienced person would tell after a bit of head scratch, the issue is with List instance as that is not thread safe.

If we replace that with a ConcurrentBag, we are good.

var tempList = new ConcurrentBag();

Old knowledge but takes a minute to kick in. Nice!!