segunda-feira, 25 de janeiro de 2016

Caching (OutputCacheAttribute e DonutCachingAttribute)

O OutputCacheAttribute, atributo nativo no ASP.NET MVC, permite que façamos cache de resultados de actions para futuras respostas às requisições dos usuários. Há várias opções de configuração e é sugerido de se utilizar esse artifício quando você precisa otimizar o desempenho de sua aplicação.

Otimizar desempenho é uma tarefa que deve ser feita de maneira muito criteriosa. Primeiro é importante você saber qual o problema atual a ser resolvido e as métricas da situação, por exemplo, está consumindo muito processamento determinada action (Atinge 100% de CPU, gasta muita memória e/ou demora muito tempo para retorno ao usuário). Deve-se tomar o cuidado para não aplicar uma solução de cache que poderá resolver os problemas anteriores, mas acabar gerando um outro problema de consumo de memória por manter as informações em cache. Por isso a importância das métricas antes e depois de aplicar a solução.

Decidindo pela aplicação do OutputCacheAttribute é importante ainda saber que ele gera um cache respeitando configurações de variação por action do Controller, por tempo (Duration), por parâmetros de unicidade (VaryByContentEncoding, VaryByCustom, VaryByHeader, VaryByParam) e por local (Client, Downstream, Server). Se for decidido que o cache será no servidor é importante saber que futuras requisições nas condições de unicidade configuradas anteriormente receberá a informação do cache completa, ou seja, se o cache foi criado pela requisição de um usuário com perfil de administrador (que tem mais opções de menu que um usuário comum), todos os usuários ao requisitarem a página em cache irão ver a página como o administrador (com as opções de menu que não deveria ver).

Se você tiver essa situação, para resolvê-la, há a teoria de cache chamada de Donut Hole Caching, que basicamente você pode escolher qual a parte do conteúdo deseja fazer cache e/ou qual deve ser atualizada automaticamente pelo contexto do usuário requisitante, este artigo em inglês explica a teoria de maneira detalhada e lúdica.

Há uma implementação de pacote para utilizar o Donut Hole Caching no pacote Nuget MvcDonutCaching que também tem o fonte disponível no Github. Neste artigo há uma explicação de todas as dificuldades e escolhas feitas para viabilizar a implementação, mas basicamente a grande sacada é que utilizando o pacote, é possível definir ChildActions como dinâmicas para serem carregadas, mesmo quando o resto da página está em cache. Para viabilizar isso o pacote adiciona  comentário HTML para marcar pontos de atualização de parte de conteúdo nas próximas requisições, quando utilizado as extensões @HtmlAction(), @Html.RenderAction() e definindo o parâmetro excludeFromParentCache, conforme código abaixo:
O ActionFilter (DonutOutputCacheAttribute) irá atualizar esses "buracos" no método OnResultExecuted.