Comece a acompanhar seu progresso
Página inicial do Trailhead
Página inicial do Trailhead

Usar o Apex assíncrono

Objetivos de aprendizagem

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

  • Saber quando usar o Apex assíncrono
  • Usar métodos futuros para lidar com um callout da web
  • Trabalhar com a interface que permite a execução em lote para processar um grande número de registros
  • Compreender as vantagens de usar a interface que permite a execução em fila quando é preciso encontrar um meio-termo

Quando ser assíncrono

Como desenvolvedor .NET, você provavelmente já foi exposto ao mundo da programação assíncrona. Vamos assumir que você já sabe o que ela é e entende os benefícios de usar esse tipo de modelo de programação. O que você talvez não saiba é quando usar a programação assíncrona na plataforma Force.com.

A escolha da programação assíncrona costuma ser embasada pelos três motivos a seguir.

  • Processar uma quantidade muito grande de registros. Esse motivo é exclusivo do mundo multilocatário do Force.com, comandado pelos limites. Os limites associados aos processos assíncronos são mais altos do que os associados aos processos síncronos. Por isso, quando você precisa processar milhares ou até milhões de registros, o processamento assíncrono é a melhor opção.

  • Fazer callouts para serviços da web externos. O processamento dos callouts pode ser bem demorado, mas no Force.com, os acionadores não podem fazer diretamente os callouts.

  • Criar uma experiência de usuário melhor e mais rápida descarregando parte do processamento nas chamadas assíncronas. Por que fazer tudo de uma vez? Se dá para esperar, deixe esperar.

Note

Nota

Não vamos entediar você explicando os detalhes de como o Salesforce garante o tratamento justo das solicitações. Mas se você estiver muito preocupado com isso, confira Asynchronous Processing in Force.com.

Métodos futuros

Quando você precisa fazer um callout a um serviço da web ou quer descarregar um processamento simples numa tarefa assíncrona, criar um método futuro pode ser a melhor saída.

Transformar um método de processamento síncrono em processamento assíncrono é incrivelmente fácil. Basta acrescentar a anotação @future ao método. Além disso, você só precisa garantir que o método é estático e retorna apenas um tipo nulo. Por exemplo, para criar um método que realize um callout a um serviço da web, podemos fazer assim:

public class MyFutureClass {
    // Include callout=true when making callouts
    @future(callout=true)    
    static void myFutureMethod(Set<Id> ids) {

        // Get the list of contacts in the future method since
        // you cannot pass objects as arguments to future methods
        List<Contact> contacts = [SELECT Id, LastName, FirstName, Email
            FROM Contact WHERE Id IN :ids];

        // Loop through the results and call a method
        // which contains the code to do the actual callout
        for (Contact con: contacts) {
            String response = anotherClass.calloutMethod(con.Id,
                con.FirstName,
                con.LastName,
                con.Email);

            // May want to add some code here to log
            // the response to a custom object
        }
    }
}

Depois, podemos chamá-lo como faríamos com qualquer outro método estático. É moleza!

Limitações dos métodos futuros

Os métodos futuros já existem há vários anos. Embora sejam uma ótima opção para os desenvolvedores do Salesforce, eles não deixam de ter desvantagens. Aqui estão algumas das limitações a considerar antes de usar um método futuro.

  • Não é possível rastrear a execução porque não é retornada uma ID de trabalho do Apex.
  • Os parâmetros precisam ser tipos de dados primitivos, matrizes de tipos de dados primitivos ou coleções de tipos de dados primitivos. Os métodos futuros não podem considerar objetos como argumentos.
  • Não é possível encadear métodos futuros e fazer com que um chame o outro.

Embora as chamadas assíncronas sejam às vezes feitas para evitar limites, ainda é necessário considerar os limites. Confira o link Execution Governors and Limits em Resources.

Apex em lote ou agendado

Outra ferramenta assíncrona muito usada é a interface que permite a execução em lote. O motivo nº 1 para alguém usá-la é a necessidade de processar um grande número de registros. Por exemplo, caso você queira limpar ou arquivar até 50 milhões de registros, a interface que permite a execução em lote é o ideal. É possível até agendar os lotes para execução em determinado momento.

Para usá-la, sua classe implementa a interface Database.Batchable. Você também define os métodos start(), execute() e finish(). Depois, é possível invocar uma classe de lote usando o método Database.executeBatch. Por exemplo, o código a seguir cria uma classe que permite a execução em lote, que processa todas as contas de uma organização e envia um email quando termina de fazer isso.

global class MyBatchableClass implements
            Database.Batchable<sObject>,
            Database.Stateful {  

    // Used to record the total number of Accounts processed
    global Integer numOfRecs = 0;

    // Used to gather the records that will be passed to the interface method
    // This method will only be called once and will return either a
    // Database.QueryLocator object or an Iterable that contains the records
    // or objects passed to the job.            
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');                
    }

    // This is where the actual processing occurs as data is chunked into
    // batches and the default batch size is 200.
    global void execute(Database.BatchableContext bc, List<Account> scope) {
        for (Account acc : scope) {
            // Do some processing here
            // and then increment the counter variable
            numOfRecs = numOfRecs + 1;
        }     
    }

    // Used to execute any post-processing that may need to happen. This
    // is called only once and after all the batches have finished.
    global void finish(Database.BatchableContext bc) {
        EmailManager.sendMail('someAddress@somewhere.com',
                              numOfRecs + ' Accounts were processed!',
                              'Meet me at the bar for drinks to celebrate');            
    }

}

Nesse caso, você poderia invocar a classe de lote usando um código anônimo como esse:

MyBatchableClass myBatchObject = new MyBatchableClass();
Database.executeBatch(myBatchObject);
Note

Nota

Não cobrimos especificamente o Apex agendado nesta unidade, mas ele é parecido com a interface que permite a execução em lote. Ele implementa a interface passível de agendamento, que pode ser usada para invocar o Apex em momentos específicos. Para saber mais sobre isso, confira o módulo Apex assíncrono.

Limitações da interface que permite a execução em lote

A interface que permite a execução em lote é excelente. No entanto, como tudo, ela também tem suas limitações.

  • A solução de problemas pode ser problemática.
  • Os trabalhos ficam em fila e estão sujeitos à disponibilidade de servidor, que às vezes pode demorar mais do que o esperado.
  • Já falamos dos limites?

E então surgiu o Apex que permite a execução em fila

Durante muito tempo, os métodos futuros e a interface que permite a execução em lote foram os principais jeitos de os desenvolvedores do Force.com fazerem o processamento assíncrono. Mas você se lembra de todas as limitações que apresentamos? Bem, elas estavam causando problemas para alguns desenvolvedores, que clamaram por uma solução melhor.

No inverno de 2015, o Salesforce atendeu ao pedido com o Apex que permite a execução em fila. Ele representa o melhor dos métodos futuros e da interface que permite a execução em lote, tudo reunido numa única superferramenta assíncrona. Os desenvolvedores que eram forçados a usar a interface, que permite a execução em lote, mais lenta para contornar as limitações dos métodos futuros podiam retornar a uma ferramenta que fazia mais sentido. O Apex que permite a execução em fila oferece os benefícios a seguir para os métodos futuros.

  • Tipos não primitivos – As classes podem aceitar variáveis de parâmetro de tipos de dados não primitivos, como sObjects ou tipos personalizados do Apex.
  • Monitoramento – Quando você envia o trabalho, é retornada uma jobId que pode ser usada para identificar o trabalho e monitorar seu progresso.
  • Encadeamento de trabalhos – É possível encadear um trabalho a outro iniciando o segundo trabalho a partir do trabalho em execução. O encadeamento de trabalhos é útil para o processamento sequencial.

Então como isso funciona? Que bom que você perguntou.

Como o Apex que permite a execução em fila contém o melhor dos métodos futuros, ele é muito mais fácil de implementar do que o Apex de lote. Ele não tem essas limitações incômodas que apresentamos aqui. Para demonstrar como ele funciona, vamos aproveitar o código de exemplo que usava um método futuro para fazer um callout da web e implementá-lo usando o Apex que permite a execução em fila.

public class MyQueueableClass implements Queueable {
    private List<Contact> contacts;

    // Constructor for the class, where we pass
    // in the list of contacts that we want to process
    public MyQueueableClass(List<Contact> myContacts) {
        contacts = myContacts;
    }

    public void execute(QueueableContext context) {
        // Loop through the contacts passed in through
        // the constructor and call a method
        // which contains the code to do the actual callout
        for (Contact con: contacts) {
            String response = anotherClass.calloutMethod(con.Id,
                    con.FirstName,
                    con.LastName,
                    con.Email);

            // May still want to add some code here to log
            // the response to a custom object
        }
    }
}

Para invocar o Apex que permite a execução em fila, você precisa de algo mais ou menos assim:

List<Contact> contacts = [SELECT Id, LastName, FirstName, Email
    FROM Contact WHERE Is_Active__c = true];
Id jobId = System.enqueueJob(new MyQueueableClass(contacts));

Quero saber mais

Além das interfaces que permitem a execução em fila, o Salesforce também introduziu a Apex Flex Queue na primavera de 2015, que eliminou a limitação de cinco lotes concomitantes. Ela também permite que os desenvolvedores monitorem e administrem a ordem dos trabalhos em fila. Confira os links em Resources para saber mais.

Este módulo apresentou aos desenvolvedores .NET as opções assíncronas disponíveis na plataforma Force.com. Para mergulhar fundo nesse tópico, aprendendo sobre testes, monitoramento de trabalhos e melhores práticas, confira o módulo Apex assíncrono.

Resources