Reputation: 17373
Background:
I'm working on Cache warmup functionality to increase the performance on ASP.NET MVC Web by pre-loading the object in Cache before it's been requested.
I'm using Azure In-Role cache, which provided AddItemLevelCallback function when Cache is updated/removed/added etc. I've shared the code logic below.
Problem:
The AddItemLevelCallback on NotifyOnceCacheIsUpdated shown in the code snippet below doesn't get invoked straight away until Item is added/updated. The request will need to wait. But the problem is the the AddItemLevelCallback is async and KickOffWarmUpCache on DAL may return before the actual item is added/updated.
What would be the elegant way to handle this scenario where KickOffWarmUpCache only returns the result to the caller only after AddItemLevelCallback is triggered.
Technology: MVC3, .NET Framework 4.5
Code Sample:
CONTROLLER
public void WarmUpCache(string id)
{
var userInfo = BLL.KickOffWarmUpCache(string id);
}
BLL
public UserInfo KickOffWarmUpCache(string id)
{
return DAL.KickOffWarmUpCache(string id)
}
DAL
public UserInfo KickOffWarmUpCache(string id)
{
UserInfo userInfo = new UserInfo();
//If Status = Progress
if (cache.Get(id).Status == "Progress")
{
NotifyOnceCacheIsUpdated(id,(result)=>
{
userInfo=result.userInfo;
});
}else{
userInfo=Cache.Get(id);
}
//This needs to wait for until callback is triggered and userInfo is populated
return userInfo;
}
UTIL
public void NotifyOnceCacheIsUpdated(string cacheKey, Action<T> callback)
{
DataCacheOperations allCacheOperations = DataCacheOperations.ReplaceItem | DataCacheOperations.AddItem ;
_ndItemLvlAllOps = cache.AddItemLevelCallback(cacheKey, allCacheOperations,
(CacheName, cacheRegion, cacheKey, itemVersion, OperationId, nd) =>
{
cachedData = cache.Get(cacheKey);
callback(cachedData);
});
}
Upvotes: 0
Views: 796
Reputation: 15772
public Task<UserInfo> KickOffWarmUpCache(string id)
{
//If Status = Progress
if (cache.Get(id).Status == "Progress")
{
var ret = new TaskCompletionSource<UserInfo>();
NotifyOnceCacheIsUpdated(id,(result)=>
{
//complete the task.
ret.SetResult(result.userInfo);
});
//return a Task...which the SetResult will complete.
return ret.Task;
}
//Return a result synchronously
return Task.FromResult(Cache.Get(id));
}
Upvotes: 1