Usar métodos futuros
Objetivos de aprendizaje
Después de completar esta unidad, tendrá conocimientos sobre lo siguiente:
- Cuándo usar los métodos futuros.
- Limitaciones de uso de métodos futuros.
- Cómo usar métodos futuros para llamadas.
- Mejores prácticas para métodos futuros.
Siga el proceso con Trail Together
¿Desea seguir el proceso con un instructor a medida que realiza este paso? Eche un vistazo a este video, que forma parte de la serie Trail Together en Trailhead Live.
(Este video comienza en el minuto 09:39 a.m., en caso de que desee rebobinar y mirar el comienzo del paso nuevamente).
Apex futuro
Los métodos Apex con la anotación @future (en este módulo los llamaremos “métodos futuros”) se ejecutan asincrónicamente en un subproceso independiente, más adelante cuando los recursos del sistema están disponibles.
Cuando se usa el procesamiento síncrono, todas las llamadas a métodos se realizan desde el mismo subproceso que ejecuta el código Apex y no se realiza ningún procesamiento adicional hasta que el proceso finaliza. Puede usar métodos futuros para cualquier operación que desee ejecutar de forma asíncrona en su propio subproceso. El procesamiento asíncrono ofrece el beneficio de no impedirle al usuario que realice otras operaciones. También ofrece límites reguladores y de ejecución superiores para el proceso. Por lo tanto, todo son ventajas en el caso del procesamiento asíncrono.
Los métodos futuros se suelen usar para lo siguiente:
- Llamadas a servicios web externos. Si va a hacer llamadas desde un desencadenador o después de realizar una operación DML, debe usar un método futuro o la interfaz
Queueable(Inclusión en cola). De lo contrario, una llamada en un desencadenador mantendría abierta la conexión con la base de datos durante todo el transcurso de la llamada, lo cual es costoso en el caso de un entorno multiusuario. - Operaciones que desea ejecutar en su propio subproceso si el tiempo lo permite, como determinados tipos de cálculo o procesamiento de registros que requieren un uso intensivo de los recursos.
- Aislamiento de operaciones DML en distintos tipos de sObject para evitar un error de mezcla de DML. Aunque se trata en cierto modo de un caso extremo, podría encontrarse con este problema ocasionalmente. Consulte sObjects que no pueden utilizarse juntos en operaciones DML para obtener más información.
Sintaxis de métodos futuros
Los métodos futuros deben ser métodos estáticos y solo pueden devolver un tipo nulo. Los parámetros especificados deben ser tipos de datos primitivos o conjuntos de tipos de datos primitivos. En concreto, los métodos futuros no pueden usar objetos estándar o personalizados como argumentos. Un patrón común es pasar al método una List (lista) de los Id. de registro que desea procesar de forma así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
}
}Es importante tener en cuenta que no está garantizada la ejecución de los métodos futuros en el mismo orden que en que se los llama. Lo repetiremos, ya que es fundamental que lo recuerde: no está garantizada la ejecución de los métodos futuros en el mismo orden en que se los llama. Cuando se usan métodos futuros, también es posible que dos métodos futuros se ejecuten simultáneamente, lo que puede provocar el bloqueo de registros y un error de tiempo de ejecución si ambos métodos actualizan el mismo registro.
Código de llamada de ejemplo
Para hacer una llamada de servicio web a un servicio o una API externos, cree una clase de Apex con un método futuro que está anotado con (callout=true). La clase siguiente incluye métodos para hacer la llamada de forma síncrona y asíncrona cuando las llamadas no están permitidas. La llamada sincrónica también inserta un registro en el objeto de registros personalizado para realizar un seguimiento del estado de la llamada.
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;
}
}Clases de prueba
La prueba de métodos futuros varía ligeramente en comparación con la prueba de Apex típica. Para probar métodos futuros, incluya el código de prueba entre los métodos de prueba startTest() y stopTest(). El sistema recopila todas las llamadas asíncronas realizadas después de startTest(). Cuando se ejecuta stopTest(), todos estos procesos asíncronos recopilados se ejecutan de forma síncrona. A continuación, puede confirmar que la llamada asíncrona ha funcionado correctamente.
Esta es la clase de llamada simulada que hemos usado para las pruebas. El marco de pruebas de Apex usa esta respuesta ‘simulada’ en lugar de hacer una llamada real al extremo de la API de 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;
}
}La clase de prueba contiene un único método de prueba (testSendSms() en este ejemplo), lo que permite probar los métodos asíncrono y síncrono cuando el primero llama al ú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);
}
}Mejores prácticas
Dado que cada invocación de un método futuro agrega una única solicitud a la cola asíncrona, evite patrones de diseño que agreguen un gran número de solicitudes futuras en un breve periodo de tiempo. Si el diseño tiene capacidad para agregar 2000 o más solicitudes a la vez, estas solicitudes se podrían retrasar debido al control de flujo.
Estas son algunas mejores prácticas que debe tener en cuenta:
- Asegúrese de que los métodos futuros se ejecuten lo más rápidamente posible.
- Si va a usar llamadas de servicio web, procure agrupar todas las llamadas del mismo método futuro en lugar de usar un método futuro independiente para cada llamada.
- Realice pruebas exhaustivas a escala. Realice una prueba para determinar si un desencadenador que pone en cola las llamadas
@futuretiene capacidad para procesar una colección de desencadenador de 200 registros. Esto ayuda a determinar si se pueden producir retrasos debido al diseño con los volúmenes actuales y futuros. - Considere la posibilidad de usar Apex por lotes en lugar de métodos futuros para procesar un gran número de registros de forma asíncrona. Esta opción es más eficiente que crear una solicitud futura para cada registro.
Aspectos que recordar
Los métodos futuros son una herramienta excelente, pero su amplia capacidad implica una gran responsabilidad. Estos son algunos de los aspectos que debe tener en cuenta cuando use estos métodos:
- Los métodos anotados como
@futuredeben ser métodos estáticos y solo pueden devolver un tipo void. - Los parámetros especificados deben ser tipos de datos primitivos o colecciones de tipos de datos primitivos. Los métodos futuros no pueden usar objetos como argumentos.
- Los métodos futuros no se ejecutan necesariamente en el mismo orden que en la llamada. Además, es posible que dos métodos futuros se ejecuten simultáneamente, lo que puede provocar el bloqueo de registros si ambos métodos actualizan el mismo registro.
- Los métodos futuros no se pueden usar en controladores de Visualforce en
getMethodName(),setMethodName()ni en el constructor. - No se puede llamar a un método futuro desde un método futuro. Tampoco puede invocar un desencadenador que llame a un método futuro mientras se ejecuta un método futuro. Para prevenir las llamadas recursivas de método futuro, use System.isFuture(), que devuelve
truesi el código que se ejecuta actualmente está invocado por código en un método futuro. - Los métodos
getContent()ygetContentAsPDF()no se pueden usar en métodos anotados como@future. - El límite es de 50 llamadas a métodos futuros por cada invocación de Apex y se aplica un límite adicional al número de llamadas en un periodo de 24 horas. Consulte Límites de ejecución y reguladores.
Recursos
- Guía del desarrollador de Apex: Métodos futuros
- Guía de referencia de Apex: Método System.isFuture()
- Guía del desarrollador de Apex: sObjects que no pueden utilizarse juntos en operaciones DML
- Guía del desarrollador de Apex: Aislamiento de los datos de prueba desde los datos de organización en las pruebas de unidad
