Apex assíncronos, são eles: Future Methods, Queueable, Batch e Scheduled, este post será uma série dividida em 4 posts, e vamos começar falando dos Future Methods (Métodos futuros), quando usar, exemplos práticos, e cobertura de classe de testes.

O que é um Future Methods?

O Apex oferece várias maneiras de executar seu código Apex de forma assíncrona, uma delas são os Future Methods, e por ele ser assíncrono, você simplesmente não pode controlar quando o mesmo será executado, ele é controlado pela plataforma Salesforce, é a plataforma que escolhe o melhor momento para a execução de um trecho de código do Apex em um Future Method e essa execução são levadas em consideração a disponibilidades de recurso disponíveis na sua org no momento de solicitação de execução.

Um dos grandes benefício de usar Future Methods é que alguns limites de governança são maiores, como por exemplo o limites de consulta SOQL e limites de tamanho de heap.

Quando usar um Future Methods?

  • Quando você tem um processo demorado e precisa prevenir atrasos em sua transação Apex
  • Quando você realiza chamada a serviços da Web externos (Por exemplo uma consulta a base de CEP de um serviço REST)
  • Para segregar operações DML e ignorar o erro de combinações de DML

Estrutura e annotation dos Future Methods

Alguns pontos devem ser levados em consideração na assinatura dos Future Methods, a primeira delas é que o método em questão deve conter acima da sua declaração, um annotation, @future, esse annotation aceita alguns parâmetros, mas falaremos deles mais a frente.

Ele também sempre deve ser static e caso você tente salvar um método com a annotation @future sem ele estar definido como estático, você receberá a seguinte mensagem de erro:

Error:(XX, XX) Future methods must be declared as static

E por último, ele sempre deve ser void, ou seja, não pode retornar nenhum valor, pois como a execução dos Future Methods são assíncronos, você nunca saberá quando ele será executado, por isso não é possível assinar um método futuro para lhe retornar algo, se você fizer isso, receberá o seguinte erro ao tentar salvar sua classe do Apex:

Error:(XX, XX) Future methods do not support return type of …

Com esse entendimento em mente, o nosso método futuro ficaria assim:

global class FutureClass
{
    @future
    public static void myFutureMethod()
    {   
         // Seu código aqui!!!
    }
}

Future Methods, podem receber valores por parâmetros, mas esses devem ser tipos de dados primitivos, arrays de tipos de dados primitivos ou coleções de tipos de dados primitivos, eles não podem receber sObjects ou objetos como argumentos.

A razão pela qual sObjects não podem ser passados ​​como argumentos para métodos futuros é porque o sObject pode mudar entre o momento em que você chama o método e a hora em que ele é executado. Nesse caso, o método futuro receberá os valores sObject antigos, e isso poderia sobrescrevê-los.

Para trabalhar com sObjects que já existem no banco de dados, passe o ID do sObject (ou coleção de IDs) e use o ID para executar uma consulta para o registro mais atualizado. O exemplo a seguir mostra como fazer isso com uma lista de IDs.

global class FutureClass
{
    @future
    public static void myFutureMethodWithParam(Set<ID> recordIds)
    {   
         // Recupera seus registros com base nos Ids enviados por parâmetro
         List<Account> accts = [SELECT Name FROM Account WHERE Id IN :recordIds];

         // Processa os registros
	 for(Account a : accts) {
		a.IsPartner = True;
	 }
				
	 update accts;
    }
}

Callout com Future Methods

A seguir, um exemplo de um método futuro que faz uma chamada para um serviço externo. Observe que a anotação leva um parâmetro extra (callout = true) para indicar que as chamadas externas são permitidas. Já falamos um pouco sobre chamadas externas nesse outro post, onde mostro como fazer a cobertura de testes para métodos que realizavam uma chamada HTTP.

global class FutureMethodExample
{
    @future(callout=true)
    public static void getCEP(String cep)
    {   
         // Realiza a chamada externa para um serviço de consulta de CEP
    }

}

Respeitando os limites dos Future Methods

Como sempre no Salesforce, temos que conviver com alguns limites, mas claro que sempre pensando no bem da plataforma como um todo, e com os métodos futuros não seriam diferentes, existem alguns limites que devemos respeitar, são eles:

  • Você pode invocar métodos futuros da mesma maneira que invoca qualquer outro método. No entanto, um método futuro não pode invocar outro método futuro
  • Você pode chamar até 50 métodos futuros em uma execução do Apex
  • Você poderá invocar no período de 24 horas o máximo de 250.000 ou o número de licenças de usuário em sua organização multiplicado por 200 em requisições de Future Methods, levando em consideração o que for maior. Esse limite é para toda sua organização e é compartilhado com todos os Apex assíncronos, veja aqui como consultar o limites da sua organização

Tarefas de métodos futuros são enfileiradas antes de um período de manutenção do serviço Salesforce, ele irá permanecer na fila. Após o término do tempo de inatividade do serviço e quando os recursos do sistema se tornarem disponíveis, as tarefas do método futuro enfileiradas serão executadas. Se um método futuro estava em execução quando iniciou o tempo de inatividade, a execução do método futuro é retrocedida e reiniciada após o serviço ser restaurado.

É possível obter alguns limites maiores em métodos futuros, mas esse é um recurso ainda não disponível para todos, e trata-se de um projeto piloto do Salesforce, ou seja você precisa se inscrever para ter acesso a ele, mais informações sobre ele podem ser obtidas aqui.

Cobertura de testes dos Future Methods

Para testar os métodos futuros, chame a classe que contém o método entre um startTest()stopTest(). Todas as chamadas assíncronas feitas após o startTest método são coletados pelo sistema. Quando o stopTest é executado, todos os processos assíncronos são executados de forma síncrona, garantindo que todos os métodos assíncronos tenham sido executados após a chamada do método stopTest().

@isTest
private class testCover {
   @isTest static void testFutureCover() {
      List<Account> accounts = new List<Account>();

      for(Integer i=0; i< 10; i++) {
         Account a = new Account();
         a.Name = 'Test ' + i;

         accounts.add(a);
      }

      insert accounts;

      //Converte as contas inseridas em um Set de Ids
      Set<Id> accountSetIds = (new Map<Id, sObject>(accounts)).keySet();

      Test.startTest();
      FutureClass.myFutureMethodWithParam(accountSetIds);
      Test.stopTest();

      // Verifica se as contas foram atualizadas
      Account[] accts = [SELECT Id from Account WHERE IsPartner = True];
      
      System.assertEquals(accounts.size(), accts.size());
   }
}

Chamadas assíncronas, como @futuro ou executeBatch, em blocos de testes utilizando um startTest stopTest, não contam nos limites para o número de trabalhos em fila.

Melhores praticas e Performance com Future Methods

O Salesforce usa uma estrutura baseada em fila para lidar com processos assíncronos. Essa fila é usada para balancear a carga de trabalho de solicitação entre organizações. Use as práticas recomendadas a seguir para garantir que sua organização use a fila de maneira eficiente para seus processos assíncronos.

  • Se possível, evite adicionar grandes números de métodos futuros à fila assíncrona. Se mais de 2.000 solicitações não processadas de uma única organização estiverem na fila, todas as solicitações adicionais da mesma organização serão atrasadas enquanto a fila manipula solicitações de outras organizações.
  • Assegure-se de que os métodos futuros sejam executados o mais rápido possível. Para garantir a execução rápida de tarefas em lote, minimize os tempos de callout do serviço da Web e ajuste as consultas usadas em seus métodos futuros. Quanto mais tempo o método futuro demorar para ser executado, mais provavelmente outras solicitações enfileiradas serão atrasadas quando houver um grande número de solicitações na fila.
  • Teste seus métodos futuros em escala. Sempre que possível, teste usando um ambiente que gere o número máximo de métodos futuros que você espera lidar. Isso ajudará a determinar se ocorrerão atrasos.
  • Considere usar o Apex em lotes (Batchs) em vez de métodos futuros para processar um grande número de registros.

 

Separei aqui alguns módulos do trailhead onde é abordado o uso de métodos futuros, não deixe de dar uma olhada nesse aqui e nesse também.

Na continuação da nossa série, falaremos das Queueable.

Um forte abraço trailblazer e até o próximo post :)

 

Fernando Sousa

Fernando Sousa

Senior Salesforce Developer

Bacharel em Sistemas da Informação pela Universidade de Taubaté (UNITAU) e MBA em Projeto de Aplicações para Dispositivos Móveis pelo IGTI – Instituto de Gestão em Tecnologia da Informação. 

Comecei a programar bem cedo, por volta de 10 anos de idade, de maneira auto-didata passei por várias linguagens.

Em 2015 me conectei a plataforma Salesforce pela primeira vez, para fazer una integração entre um Aplicativos Mobile em android e o Salesforce Platform. 

Atualmente com as certificações Salesforce Certified Platform Developer I, Salesforce Certified Platform App BuilderSalesforce Certified Platform Developer IISalesforce Administrator e Sharing and Visibility.

Acompanhe meu Trailhead aqui.