In a web application, I want to cache heavy calls into the db. So I want to do ansyc reads, store the result from read and transformation in a store and present the newest data I have available at the time of the request (sometimes stale)
// that is the entry point
public virtual IViewData DetailByKey(string key)
{
var articleDetailPage = GetArticleDetailViewModel(key);
if (articleDetailPage == null)
return new PageBase(ActionResult.Failure, _messages.ArticleNotFound,
FexUrl.For("Search", "Search", new { query = key }));
return articleDetailPage;
}
// here I see if I have it in the cache, and return it if so.
// if the item is exipred, I want it to be generated, so that subsequent
// requests get new data. The actual request gets stale data, but fast.
ArticleDetailPage GetArticleDetailViewModel(string key)
{
var cacheKey = "Product#" + key;
var cached = _cache.Get(cacheKey);
if (cached == null)
{
return GenerateViewModelAndPutIntoCache(key, cacheKey);
}
if (cached.HasExpired())
{
var t = new Thread(() => GenerateViewModelAndPutIntoCache(key, cacheKey))
{
Name = "Caching article detail"
};
t.Start();
t.Join(TimeSpan.FromSeconds(5));
}
return cached.Data;
}
ArticleDetailPage GenerateViewModelAndPutIntoCache(string key, string cacheKey)
{
ArticleDetailPage page = null;
using (var uow = UnitOfWork.Start())
using (var tx = uow.BeginTransaction())
{
try
{
// this might work, because we will start this fast enough
// and the uow will get it's ISession from the application request store
var product = _productDao.GetByKey(key);
// of course I would want to have a private ISession here
// but how do I get it?
if (product == null)
return null;
page = ArticleDetailPageBuilder.Build(product, _articleService, FexUrl,
_classificationService, _messages);
_cache.Put(new CachedArticleDetailViewData(page, 1), cacheKey);
tx.Commit(); // this will fail request is long finished here
return page;
}
catch(Exception ex)
{
tx.Rollback();
Logger.Error("Could not cache article detail data.", ex);
}
} // fail, nothing there anymore
return page;
}
Any ideas on how to tackle this?