Usar métodos futuros
Objetivos de aprendizagem
Após concluir esta unidade, você saberá:
- Quando usar métodos futuros.
- As limitações para o uso de métodos futuros.
- Como usar métodos futuros para callouts.
- Melhores práticas para método futuro.
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 09:39 minutos, caso você queira retroceder e ver o início da etapa novamente.)
Apex futuro
Os métodos do Apex com a anotação @future (referidos no restante deste módulo como “métodos futuros”) são executados de forma assíncrona em um thread separado, posteriormente, quando os recursos do sistema estiverem disponíveis.
Ao usar o processamento sincronizado, todas as chamadas de método são feitas a partir do mesmo thread que está executando o código do Apex e nenhum processamento adicional pode ocorrer até que o processo seja concluído. Você pode usar métodos futuros para qualquer operação que quiser para executar de forma assíncrona em seu próprio thread. O processamento assíncrono oferece a vantagem de não impedir o usuário de realizar outras operações. Ele também oferece limites mais altos de administrador e de execução para o processo. Todos saem vencedores com o processamento assíncrono.
Métodos futuros normalmente são utilizados para:
- Fazer callouts para serviços da Web externos. Se você estiver fazendo callouts a partir de um acionador ou após realizar uma operação DML, tem que usar um método futuro ou a interface
Queueable(Que permite a execução em fila). Caso contrário, um callout em um acionador manteria a conexão com o banco de dados aberta pela duração do callout, o que é dispendioso em um ambiente multilocatário. - Operações que você deseja executar em seu próprio thread, quando o tempo permitir, como um tipo de cálculo ou processamento de registros com consumo intenso de recursos.
- Isolar operações DML em diferentes tipos de sObject para evitar o erro de DML combinada. Isto é um caso extremo, mas você pode passar por este problema. Consulte sObjects que não podem ser usados juntos em operações DML para obter mais detalhes.
Sintaxe do método futuro
Os métodos futuros têm de ser métodos estáticos e só podem retornar um tipo void. Os parâmetros especificados precisam ser tipos de dados primitivos ou coleções de tipos de dados primitivos. Em especial, métodos futuros não podem lidar com objetos padrão ou personalizados como argumentos. Um padrão comum é passar ao método uma List (Lista) de IDs de registros que você deseja processar de forma assíncrona.
public class SomeClass {
@future
public static void someFutureMethod(List<Id> recordIds) {
List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds];
// process account records to do awesome stuff
}
}É importante notar que não é garantido que os métodos futuros sejam executados na mesma sequência em que foram chamados. Vamos repetir porque é crucial que você se lembre: não é garantido que métodos futuros sejam executados na mesma sequência em que foram chamados. Ao usar métodos futuros, também é possível que dois métodos futuros possam ser executados simultaneamente, o que poderia resultar em bloqueio de registro e em um erro de tempo de execução se os dois métodos estiverem atualizando o mesmo registro.
Amostra de código de callout
Para fazer um callout de um serviço da Web para um serviço ou API, crie uma classe do Apex com um método futuro anotado com (callout=true). A classe abaixo tem métodos para fazer o callout de forma síncrona e assíncrona onde callouts não são permitidos. A chamada síncrona também insere um registro em um objeto do log personalizado para rastrear o status do callout.
public class SMSUtils {
// Call async from triggers, etc, where callouts are not permitted.
@future(callout=true)
public static void sendSMSAsync(String fromNbr, String toNbr, String m) {
String results = sendSMS(fromNbr, toNbr, m);
System.debug(results);
}
// Call from controllers, etc, for immediate processing
public static String sendSMS(String fromNbr, String toNbr, String m) {
// Calling 'send' will result in a callout
String results = SmsMessage.send(fromNbr, toNbr, m);
insert new SMS_Log__c(to__c=toNbr, from__c=fromNbr, msg__c=results);
return results;
}
}Classes de teste
Testar métodos futuros é um pouco diferente do teste de Apex típico. Para testar métodos futuros, inclua seu código de teste entre os métodos de teste startTest() e stopTest(). O sistema coleta todas as chamadas assíncronas feitas após startTest(). Quando o método stopTest() é executado, todos estes processos assíncronos coletados são executados de forma síncrona. Então é possível afirmar se a chamada assíncrona operou corretamente.
Aqui está nossa classe de callout simulado usado para o teste. A estrutura de teste do Apex usa essa resposta “simulada” em vez de fazer o callout real para o ponto de extremidade da API REST.
@isTest
public class SMSCalloutMock implements HttpCalloutMock {
public HttpResponse respond(HttpRequest req) {
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"status":"success"}');
res.setStatusCode(200);
return res;
}
}O teste de classe contém apenas um método de teste (testSendSms() neste exemplo), que testa ambos os métodos assíncrono e síncrono à medida que o primeiro chama este último.
@IsTest
private class Test_SMSUtils {
@IsTest
private static void testSendSms() {
Test.setMock(HttpCalloutMock.class, new SMSCalloutMock());
Test.startTest();
SMSUtils.sendSMSAsync('111', '222', 'Greetings!');
Test.stopTest();
// runs callout and check results
List<SMS_Log__c> logs = [select msg__c from SMS_Log__c];
System.assertEquals(1, logs.size());
System.assertEquals('success', logs[0].msg__c);
}
}Melhores práticas
Como toda invocação de método futuro adiciona uma solicitação à fila assíncrona, evite projetar padrões que adicionem grandes números de solicitações futuras em um curto período de tempo. Se seu projeto tem o potencial de adicionar 2.000 ou mais solicitações de uma vez, as solicitações podem ser atrasadas devido ao controle de fluxo.
Aqui estão algumas das melhores práticas que você deve manter em mente:
- Verifique se os métodos futuros estão sendo executados o mais rápido possível.
- Se você estiver usando callouts de serviço da Web, tente agrupar todos os callouts do mesmo método futuro, em vez de usar um método futuro separado para cada callout.
- Realize testes completos na escala. Teste se um acionador que coloca na fila as chamadas
@futureé capaz de lidar com uma coleção de acionadores com 200 registros. Isto ajuda a determinar se podem ocorrer atrasos devido ao projeto nos volumes atuais e futuros. - Considere usar o Apex de lote em vez de métodos futuros para processar um grande número de registros de forma assíncrona. Isto é mais eficiente que criar uma solicitação de futuro para cada registro.
Coisas a serem lembradas
Métodos futuros são uma ótima ferramenta, mas com grandes poderes vêm também grandes responsabilidades. Aqui estão algumas coisas para manter em mente ao usá-los:
- Métodos com a anotação
@futuretêm que ser estáticos e só podem retornar um tipo void. - Os parâmetros especificados têm de ser tipos de dados primitivos ou coleções de tipos de dados primitivos. Métodos futuros não podem ter objetos como argumentos.
- Métodos futuros não são executados necessariamente na mesma ordem em que são chamados. Além disso, é possível que dois métodos futuros sejam executados simultaneamente, o que poderia resultar em bloqueio de registro se os dois métodos estivessem atualizando o mesmo registro.
- Os métodos futuros não podem ser usados com controladores Visualforce em
getMethodName(),setMethodName()nem no construtor. - Não é possível chamar um método futuro a partir de um método futuro. Também não é possível invocar um acionador que chame um método futuro enquanto executa um método futuro. Para evitar chamadas recursivas de métodos futuros, use System.isFuture(), que retorna
truese o código atualmente em execução for invocado por código contido em um método futuro. - Os métodos
getContent()egetContentAsPDF()não podem ser usados em métodos com a anotação@future. - Há uma limitação de 50 chamadas futuras por invocação Apex e um limite adicional no número de chamadas em um período de 24 horas. Consulte Administradores e limites de execução.
Recursos
- Guia do desenvolvedor do Apex: Métodos futuros
- Guia de referência do Apex: Método System.isFuture()
- Guia do desenvolvedor do Apex: sObjects que não podem ser utilizados juntos em operações DML
- Guia do desenvolvedor do Apex: Isolation of Test Data from Organization Data in Unit Tests
