Controlar processos com o Apex que permite a execução em fila
Objetivos de aprendizagem
Após concluir esta unidade, você saberá:
- Quando usar a interface
Queueable
(Que permite a execução em fila). - As diferenças entre os métodos futuro e que permite a execução em fila.
- A sintaxe do Apex que permite a execução em fila.
- Melhores práticas para o método que permite a execução em fila.
Acompanhar com o Trail Together
Deseja acompanhar um instrutor enquanto trabalha nesta etapa? Veja este vídeo que faz parte da série Trail Together no Trailhead Live.
(Este clipe começa na marca dos 52:38 minutos, caso você queira retroceder e ver o início da etapa novamente.)
Apex que permite a execução em fila
Lançado na versão Winter ‘15, o Apex que permite a execução em fila é basicamente um superconjunto de métodos futuros com algum #temperoextra. Pegamos a simplicidade dos métodos futuros e o poder do Apex de lote e os combinamos para gerar o Apex que permite a execução em fila! Ele lhe oferece uma estrutura de classes que a plataforma serializa para você, uma interface simplificada sem métodos start e finish e que permite inclusive que você use mais do que apenas argumentos primitivos! Para chamá-lo, basta usar o método System.enqueueJob()
, que ele retornará uma ID do trabalho que pode ser monitorada. É muito fácil!
O Apex que permite a execução em fila permite enviar trabalhos para processamento assíncrono, da mesma forma que os métodos futuros, com os seguintes benefícios adicionais:
- Tipos não primitivos: Sua classe
Queueable
(Que permite a execução em fila) pode conter variáveis de membro de tipos de dados não primitivos, como sObjects ou tipos personalizados do Apex. Tais objetos podem ser acessados quando o trabalho for executado. - Monitoramento: Quando você envia o trabalho invocando o método
System.enqueueJob()
, o método retorna a ID do registro AsyncApexJob. É possível usar este ID para identificar seu trabalho e monitorar seu progresso, seja pela interface de usuário do Salesforce, na página de Trabalhos do Apex, seja programaticamente pela consulta de seu registro em AsyncApexJob. - Encadeamento de trabalhos: É possível encadear um trabalho a outro iniciando o segundo trabalho a partir de um trabalho em execução. O encadeamento de trabalhos é útil se você precisar fazer algum processamento sequencial.
Apex que permite a execução em fila versus Futuro
Como os métodos que permitem a execução em fila são funcionalmente equivalentes aos métodos futuros, na maioria das vezes você provavelmente preferirá usar os métodos que permitem a execução em fila. Porém, isso não significa necessariamente que você deva voltar e refazer todos os seus métodos futuros agora.
Outro motivo para usar métodos futuros em vez dos que permitem a execução em fila é quando sua funcionalidade é executada às vezes de modo síncrono e às vezes de modo assíncrono. É muito mais fácil refazer um método desta forma que convertê-lo em uma classe que permite a execução em fila. Isso é muito prático quando você descobre que parte de seu código atual precisa ser transferido para uma execução assíncrona. Você pode simplesmente criar um método futuro semelhante que envolva seu método síncrono, da seguinte forma:
@future static void myFutureMethod(List<String> params) { // call synchronous method mySyncMethod(params); }
Sintaxe do Apex que permite a execução em fila
Para usar o Apex que permite a execução em fila, basta implementar a interface Que permite a execução em fila
.
public class SomeClass implements Queueable { public void execute(QueueableContext context) { // awesome code here } }
Código de exemplo
Um cenário comum é pegar alguns conjuntos de registros sObject, executar algum processamento, como fazer um callout para um ponto de extremidade REST externo ou realizar alguns cálculos e então atualizá-los no banco de dados de forma assíncrona. Como os métodos @future
são limitados a tipos de dados primitivos (ou coleções de dados primitivos), o Apex que permite a execução em fila é a opção ideal. O código a seguir pega uma coleção de registros de Conta, define a parentId
para cada registro, e então atualiza os registros no banco de dados.
public class UpdateParentAccount implements Queueable { private List<Account> accounts; private ID parent; public UpdateParentAccount(List<Account> records, ID id) { this.accounts = records; this.parent = id; } public void execute(QueueableContext context) { for (Account account : accounts) { account.parentId = parent; // perform other processing or callout } update accounts; } }
Para adicionar esta classe como um trabalho na fila, execute o seguinte código:
// find all accounts in ‘NY’ List<Account> accounts = [select id from account where billingstate = ‘NY’]; // find a specific parent account for all records Id parentId = [select id from account where name = 'ACME Corp'][0].Id; // instantiate a new instance of the Queueable class UpdateParentAccount updateJob = new UpdateParentAccount(accounts, parentId); // enqueue the job for processing ID jobID = System.enqueueJob(updateJob);
Após enviar sua classe que permite a execução em fila para a execução, o trabalho será adicionado à fila e processado quando os recursos do sistema se tornarem disponíveis.
Você pode usar o novo ID para monitorar o progresso por meio da página de Trabalhos do Apex ou, programaticamente, consultando AsyncApexJob:
SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID
Como testar o Apex que permite a execução em fila
O exemplo de código a seguir mostra como testar a execução de um trabalho que permite a execução em fila em um método de teste. Isso é muito semelhante ao teste do Apex de lote. Para garantir que o processo que permite a execução em fila seja executado no método de teste, o trabalho é enviado à fila entre os blocos Test.startTest
e Test.stopTest
. O sistema executa todos os processos assíncronos iniciados em um método de teste de forma síncrona após a instrução Test.stopTest
. A seguir, o método de teste verifica os resultados do trabalho que permite a execução em fila consultando os registros de conta que foram atualizados pelo trabalho.
@isTest public class UpdateParentAccountTest { @testSetup static void setup() { List<Account> accounts = new List<Account>(); // add a parent account accounts.add(new Account(name='Parent')); // add 100 child accounts for (Integer i = 0; i < 100; i++) { accounts.add(new Account( name='Test Account'+i )); } insert accounts; } static testmethod void testQueueable() { // query for test data to pass to queueable class Id parentId = [select id from account where name = 'Parent'][0].Id; List<Account> accounts = [select id, name from account where name like 'Test Account%']; // Create our Queueable instance UpdateParentAccount updater = new UpdateParentAccount(accounts, parentId); // startTest/stopTest block to force async processes to run Test.startTest(); System.enqueueJob(updater); Test.stopTest(); // Validate the job ran. Check if record have correct parentId now System.assertEquals(100, [select count() from account where parentId = :parentId]); } }
Como encadear trabalhos
Um dos melhores recursos do Apex que permite a execução em fila é o encadeamento de trabalhos. Se você precisar executar trabalhos sequencialmente, o Apex que permite a execução em fila pode deixar sua vida muito mais fácil. Para encadear um trabalho a outro, envie o segundo trabalho a partir de um método execute()
de sua classe que permite a execução em fila. Só é permitido adicionar um trabalho a partir de um trabalho em execução, o que significa que apenas um trabalho filho pode existir para cada trabalho pai. Por exemplo, se houver uma segunda classe chamada SecondJob
que implemente a interface Que permite a execução em fila
, será possível adicionar esta classe à fila no método execute()
da seguinte forma:
public class FirstJob implements Queueable { public void execute(QueueableContext context) { // Awesome processing logic here // Chain this job to next job by submitting the next job System.enqueueJob(new SecondJob()); } }
Novamente, o teste tem um padrão ligeiramente diferente. Não é possível encadear trabalhos que permitem a execução em fila em um testo do Apex. Isso resultaria em um erro. Para evitar erros graves, é possível verificar se o Apex está sendo executado em contexto de teste com a chamada de Test.isRunningTest()
antes de encadear os trabalhos.
Coisas a serem lembradas
O Apex que permite a execução em fila é uma excelente ferramenta nova, mas há algumas coisas às quais é preciso estar atento:
- A execução de um trabalho em fila é contada uma vez para o limite compartilhado para execuções do método Apex assíncrono.
- Você pode adicionar até 50 trabalhos à fila com o
System.enqueueJob
em uma só transação. - Ao encadear trabalhos, você só pode adicionar um trabalho a partir de um trabalho em execução com
System.enqueueJob
, o que significa que apenas um trabalho filho pode existir para cada trabalho pai que permite a execução em fila. Iniciar diversos trabalhos filhos no mesmo trabalho que permite a execução em fila não é aceitável. - Nenhum limite é imposto à profundidade dos trabalhos encadeados, o que significa que você pode encadear um trabalho atrás do outro e repetir esse processo, encadeando-o a outro trabalho filho. Porém, para as versões de Developer Edition e Organizações de teste, a profundidade máxima da pilha para trabalhos encadeados é de cinco, o que significa que você pode encadear trabalhos quatro vezes e o número máximo de trabalhos na cadeia é de cinco, incluindo o trabalho que permite a execução em fila pai inicial. No entanto, esse limite pode ser substituído pelo recurso Configure Stack Depth of Chained Queueable Jobs (Configurar profundidade da pilha de trabalhos enfileirados em cadeia).
Recursos