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, 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
Apex futuro se usa para ejecutar procesos en un subproceso independiente y en un momento posterior en el que los recursos del sistema estén disponibles.
Nota: Técnicamente, debe usar la anotación @future
para identificar los métodos que se ejecutan de forma asíncrona. No obstante, dado que los "métodos identificados con la anotación @future
" son laboriosos, se suelen llamar "métodos futuros" y así es como haremos referencia a ellos en el resto de este módulo.
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. Las ventajas son que de este modo no se impide al usuario que realice otras operaciones y además se aplican límites reguladores y de ejecución superiores al 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 válido para la inclusión en cola. 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 inaceptable en el caso de un entorno de múltiples arrendatarios.
- 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 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 se garantiza la ejecución de los métodos futuros en el mismo orden que en la llamada. Lo diremos de nuevo ya que es fundamental que lo recuerde: no se garantiza la ejecución de los métodos futuros en el mismo orden que en la llamada. 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 grave 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, debe crear una clase de Apex con un método futuro marcado con (callout=true)
. La clase siguiente incluye métodos para hacer la llamada de forma síncrona y de forma asíncrona, aunque las llamadas no se permiten. En realidad, hemos insertado un registro en un objeto de registro personalizado para hacer un seguimiento del estado de la llamada por el mero hecho de que las tareas de registro siempre son divertidas.
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
@future
tiene 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
@future
deben 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. Además, no puede invocar un desencadenador que llame a un método futuro mientras se ejecuta un método futuro. Consulte el vínculo de la sección Recursos para obtener información sobre cómo evitar las llamadas a métodos futuros recurrentes.
- 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. Para obtener más información sobre los límites, consulte el vínculo incluido a continuación.
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: Límites de ejecución y reguladores
- Guía del desarrollador de Apex: Aislamiento de los datos de prueba desde los datos de organización en las pruebas de unidad