Percorrer um aplicativo de exemplo e descobrir o diagnóstico de cache

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:

  • Explicar um padrão para armazenar e atualizar dados em cache.
  • Decidir sobre a estrutura de dados a ser usada para o valor em cache.
  • Diagnosticar seu uso de cache.

Guia passo a passo do aplicativo de exemplo

Vamos dar uma olhada em um aplicativo de exemplo que demonstra como usar o cache da organização para armazenar e recuperar taxas de câmbio de moedas. As taxas de câmbio flutuam durante o dia, ou seja, esse aplicativo não retorna taxas em tempo real. O aplicativo oferece apenas um panorama diário das taxas de câmbio. Como não estamos interessados em valores exatos em tempo real, apenas em valores diários, armazenar as taxas de câmbio em cache é uma boa opção. Quando as taxas de câmbio são recuperadas repetidamente, obtê-las do cache economiza bastante tempo e melhora o desempenho do aplicativo.

Visão geral do aplicativo de exemplo

Baseamos nosso aplicativo de exemplo de taxas de câmbio em uma página do Visualforce e em um controlador do Apex que contém a lógica de busca das taxas de câmbio. Quando a página é acessada pela primeira vez, as taxas são obtidas por meio de chamada da API para um serviço web externo. As execuções posteriores dessa página retornarão as taxas do cache se elas estiverem lá há menos de 24 horas. Para cada taxa de câmbio, essa página exibe a moeda base, a moeda de conversão desejada e o valor de conversão. Para fins ilustrativos, um pequeno conjunto de moedas é retornado.

Página do Visualforce exibindo taxas de câmbio

Esse exemplo é a marcação da página do Visualforce. Essa página está associada ao controlador do Apex ExchangeRates.

<apex:page controller="ExchangeRates" action="{!init}">
    
   <apex:pageBlock title="Rates">
      <apex:pageBlockTable value="{!Rates}" var="rate">
         <apex:column value="{!rate.Base_Currency__c}"/>
         <apex:column value="{!rate.To_Currency__c}"/>
         <apex:column value="{!rate.Rate__c }"/>
      </apex:pageBlockTable>
   </apex:pageBlock>
   
</apex:page>

Controlador do Apex de exemplo

Nosso controlador do Apex de exemplo é que faz o trabalho pesado. Ele busca as taxas de câmbio, armazena essas taxas no Salesforce e no cache e as recupera do cache. Vejamos o detalhamento das operações que o controlador de exemplo realiza, seguido do código-fonte.

Quando o exemplo é executado pela primeira vez, ocorrem as seguintes operações:

  • As taxas de câmbio são obtidas de uma chamada de API para um ponto de extremidade externo.
  • O resultado (em formato JSON) retornado pela chamada de API é analisado e salvo em sObjects Exchange_Rate_c no Salesforce.
  • O método getCachedRates() armazena a matriz de sObjects Exchange_Rate__c no cache da organização.

Nas execuções seguintes do exemplo:

  • O exemplo verifica o tempo de armazenamento dos dados. Para isso, ele realiza uma consulta SOQL para buscar o valor createdDate do primeiro registro Exchange_Rate_c.
  • Se os dados tiverem mais de um dia, as taxas de câmbio serão obtidas pela chamada de API, como na primeira execução.
  • Se os dados tiverem menos de um dia, as taxas serão retiradas do cache da organização. Se houver uma falha de cache, as taxas são consultadas em sObjects Exchange_Rate_c e armazenadas no cache da organização.
Nota

Nota

O controlador do Apex usa uma classe do Apex auxiliar chamada RateLib, que não é mostrada aqui. Essa classe auxiliar contém métodos para fazer a chamada de API para um serviço de câmbio, analisar o resultado JSON da chamada de API e armazenar registros Exchange_Rate_c.

public class ExchangeRates {
    private String currencies = 'EUR,GBP,CAD,PLN,INR,AUD,SGD,CHF,MYR,JPY,CNY';
    public String getCurrencies() { return currencies;}
    public Exchange_Rate__c[] rates {get; set;}

    //                                                                          
    // Checks if the data is old and gets new data from an external web service 
    // through a callout. Calls getCachedRates() to manage the cache.           
    // 
    public void init() {
        // Let's query the latest data from Salesforce
        Exchange_Rate__c[] latestRecords = ([SELECT CreatedDate FROM Exchange_Rate__c 
                        WHERE Base_Currency__c =:RateLib.baseCurrencies 
                              AND forList__c = true 
                        ORDER BY CreatedDate DESC
                        LIMIT 1]);
        
        // If what we have in Salesforce is old, get fresh data from the API
        if ( latestRecords == null  
            || latestRecords.size() == 0 
            || latestRecords[0].CreatedDate.date() < Datetime.now().date()) {
            // Do API request and parse value out
            String tempString = RateLib.getLoadRate(currencies);
            Map<String, String> apiStrings = RateLib.getParseValues(
                tempString, currencies);
            
            // Let's store the data in Salesforce
            RateLib.saveRates(apiStrings);

            // Remove the cache key so it gets refreshed in getCachedRates()
            Cache.Org.remove('Rates');
        }
        // Call method to manage the cache
        rates = getCachedRates();
    }

    //                                                                          
    // Main method for managing the org cache.                                  
    // - Returns exchange rates (Rates key) from the org cache.                 
    // - Checks for a cache miss.                                               
    // - If there is a cache miss, returns exchange rates from Salesforce       
    //    through a SOQL query, and updates the cached value.                   
    //
    public Exchange_Rate__c[] getCachedRates() {
        // Get the cached value for key named Rates
        Exchange_Rate__c[] rates = (Exchange_Rate__c[])Cache.Org.get(
            RateLib.cacheName+'Rates');
        
        // Is it a cache miss? 
        if(rates == null) {
            // There was a cache miss so get the data via SOQL
            rates = [SELECT Id, Base_Currency__c, To_Currency__c, Rate__c 
                        FROM Exchange_Rate__c 
                        WHERE Base_Currency__c =:RateLib.baseCurrencies 
                              AND forList__c = true
                              AND CreatedDate = TODAY];
            // Reload the cache
            Cache.Org.put(RateLib.cacheName+'Rates', rates);
        }
        return rates;
    }
}

Para baixar a fonte do exemplo Taxas de câmbio e experimentá-la em sua organização de desenvolvedor, consulte a seção Recursos.

Melhores práticas de gerenciamento de cache

Padrão de armazenamento em cache

A classe do Apex ExchangeRates contém métodos que encapsulam a lógica de inicializar e atualizar o cache. Se os dados estiverem desatualizados ou não forem encontrados, o método init() recupera novas taxas de câmbio por meio de uma chamada de API e as armazena no Salesforce. O método getCachedRates() gerencia o cache internamente. Se o valor em cache não for encontrado, esse método recuperará uma matriz de taxas do Salesforce e a armazenará no cache.

Como nosso aplicativo usa dados externos, ele busca dados de um serviço web por meio de chamadas de API. Ele também armazena os dados como registros Salesforce para backup de atualização do cache. Os aplicativos que não usam dados externos recuperam registros Salesforce usando SOQL e armazenando-os em cache. Nesse caso, o processo de gerenciamento de cache é mais simples e a implementação do método de cache é mais rápida. Por exemplo, se seu aplicativo usa somente dados locais de SOQL, você não precisará do método init(); apenas do método getCachedRates().

Recomendamos que você inclua toda a lógica para gerenciar o cache em um método. Assim, o cache é manipulado em um mesmo lugar em seu aplicativo. O gerenciamento central do cache reduz a probabilidade de erros de acesso a cache inválido (falha de cache) ou a substituição de valores em cache por acidente.

Como decidir o que armazenar em cache

Este exemplo armazena uma matriz de sObjects no cache. Essa abordagem é a melhor escolha de estrutura de dados para armazenamento? Cada escolha tem seus prós e contras. O armazenamento de menos dados, como valores de campo em vez de sObjects inteiros, pode reduzir o tamanho de seu uso de cache. Mas se você armazenar menos dados em cada chave, poderá precisar de lógica complexa para recompilar os dados e sObjects, o que exige mais tempo de processamento. E uma matriz de sObjects armazenada em uma chave usa menos espaço de cache que o tamanho total de sObjects individuais armazenados em chaves individuais. O armazenamento de itens menores em vez de uma lista de itens piora o desempenho de cache por conta da sobrecarga da serialização e do tempo de confirmação do cache. Por exemplo, em vez de armazenar uma lista de taxas (referenciada pela variável rates neste trecho de código):

Cache.Org.put('Rates', rates);

Você pode armazenar as taxas individualmente, cada uma como um campo com sua própria chave de cache, como mostrado a seguir.

Cache.Org.put('DollarToEuroRate', rateEUR);
Cache.Org.put('DollarToChineseYuan', rateCNY);
Cache.Org.put('DollarToJapaneseYen', rateJPY);
// etc.

A decisão sobre a estrutura de dados para armazenar em cache depende do que seu aplicativo faz com os dados. Por exemplo, se o aplicativo converte valores usando a mesma moeda de base, armazene, no mínimo, a taxa de câmbio para cada moeda desejada. Você pode armazenar cada taxa de câmbio como uma chave individual. Mas, para facilitar a exibição das taxa em uma página do Visualforce, armazene os dados em cache como uma lista de sObject. Os sObjects podem aumentar o espaço de armazenamento porque contêm campos de sistema, como a data de criação, mas reduzem o tempo de processamento da lógica e melhoram o desempenho do aplicativo e do cache. Lembre-se de que ao usar o cache, o principal objetivo é reduzir o tempo de execução do aplicativo.

Diagnosticar uso de cache

Bom, você fez tudo isso para implementar o cache da plataforma. Como você sabe se está usando o cache da melhor maneira? Existem duas maneiras de verificar dados de desempenho. Uma delas é ver as informações de diagnóstico em Configuração (disponível somente no Salesforce Classic).

Antes de acessar a página de diagnóstico, habilite a permissão de diagnóstico de cache para seu usuário.

  1. Em Configuração, insira usuários na caixa Busca rápida e selecione Usuários.
  2. Clique no nome do usuário e clique em Editar.
  3. Selecione Diagnóstico de cache e clique em Salvar.

Em seguida, acesse a página de diagnóstico de um tipo de cache específico em uma partição.

  1. Em Configuração, insira cache na caixa Busca rápida e selecione Cache da plataforma.
  2. Clique na partição da qual você deseja verificar as informações de diagnóstico.
  3. No cache da sessão ou da organização, clique em Diagnóstico.

    A página da partição contém links para as páginas de diagnóstico de cada tipo de cache

Se você clicar em Diagnóstico do cache da organização, a página Diagnóstico do cache da organização será aberta em uma nova guia. Essa página mostra dois gráficos. O primeiro gráfico (Capacidade e uso do cache da organização) mostra seu limite de uso do cache. Em nosso caso, estamos bem abaixo do limite, em 0,02%. O segundo gráfico (Por contribuição de conteúdo) é um gráfico de rosca que mostra a distribuição de cache por chave.

Nota

Nota

Como nosso exemplo usa o cache da organização, estamos inspecionando a página de diagnóstico somente para o cache da organização. Uma página de diagnóstico semelhante também é fornecida para o cache da sessão no caso de aplicativos que usam o cache da sessão.

A imagem a seguir mostra um gráfico de distribuição de conteúdo com quatro chaves de cache. Uma das chaves de cache, Rates, é usada em nosso exemplo de taxas de câmbio. A chave Rates usa mais de metade do espaço.

Página de diagnóstico para o cache da organização

Depois dos gráficos são listados os detalhes das chaves de cache. A lista fornece o tamanho de cada valor em cache correspondente a uma chave e a quantidade de vezes que o cache foi acessado. Você pode excluir um cache dessa lista manualmente como alternativa a chamar o método remove() no Apex. O botão Excluir permite que os administradores gerenciem o cache sem modificar código.

A chave DollarToEuroRate usa muito menos espaço que a chave Rates. Isso ocorre porque DollarToEuroRate armazena somente um valor, ao passo que Rates armazena uma matriz de sObjects.

Use as informações na página de diagnósticos para determinar se é necessário ajustar seu uso do cache. Por exemplo, se um valor de cache tiver uma contagem de acessos baixa, indicando que é usado raramente, pergunte-se se ele é realmente necessário, especialmente se for grande. Ou, se estiver se aproximando o limite de uso do cache, pense no que você deve armazenar nele. Talvez seja ideal remover valores de cache desnecessários ou comprar mais capacidade de cache.

Parabéns! Você aprendeu a usar o cache da plataforma para armazenar os dados de seu aplicativo em cache para agilizar a recuperação. Você também viu as melhores práticas de armazenamento em cache e como diagnosticar o uso do cache. Agora você está pronto para se juntar aos esquilos e armazenar recursos preciosos!