views:

24

answers:

0

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?