Anteriormente he hablado de Batch , y seguramente volveré con ello , pero hoy quiero hablar de otro proceso asíncrono al que no le tenia tanto cariño.
¿Conocéis @future?
Pues bien este es otro proceso asíncrono que podemos usar dentro de la plataforma Salesforce.
La gran cualidad de los procesos asíncronos es que tienen limites especiales los cuales son mayores a los procesos o transacciones síncronos.
Échale un vistazo a los Governos Limits en esta página: Governor limits
Como ves el número de registros, tanto como el tiempo , número de consultas SOQL es mayor que en una transacción síncrona.
Luego usar procesos asíncronos como @future o Batch Jobs es muy beneficiosos para algunos casos siempre y cuando no necesites el resultado .. ¡Ya!
Hoy me voy a centrar en @future y su “Futuro” la interfaz Queueable.
Pues bien, métodos @future se ejecutan cuando Salesforce tiene recursos disponibles.
Las limitaciones que existen en estos métodos son las siguientes:
- Deben ser métodos estáticos : static
- Solamente son de tipo void , no podemos devolver ningún otro tipo
- No tenemos forma de saber en que estado se encuentran
- No podemos cancelarlos
- No son ejecutados en el orden que son llamados
- No se pueden encadenar
- Los parámetros que podemos usar son solamente “primitivos” , no podemos usar sObjets por ejemplo.
Esta es la nomenclatura usada :
public with sharing class FutureClass { @future static void myMethod(String a, Integer i) { System.debug('Method called with: ' + a + ' and ' + i+'... and I loved the sunny days :)'); // Aquí va nuestro código, toda la lógica } }
Es en este punto… donde aparece la ¡Interfaz Queueable!!
Que desde Winter 15 nos va a permitir:
- Poder saber el estado de nuestro proceso asíncrono
- Poder cancelarlo
- Poder encadenar procesos
- Poder usar cualquier tipo de parámetros
Y así es como se puede implementar:
public class AsyncExecutionExample implements Queueable { public void execute(QueueableContext context) { //escribo mi lógica } }
Como veis el ejemplo nos muestra el método principal que debemos sobreescribir: execute
Dentro de dicho método es donde pondremos toda nuestra lógica, donde procesaremos todos los registros que necesitamos.
¿Cómo deberíamos entonces lanzar or llamar este proceso?
ID jobID = System.enqueueJob(new AsyncExecutionExample());
Entonces es aquí una vez el proceso se ha llamado podemos ver el estado en el que se encuentra haciendo una consulta a la tabla de procesos asíncronos :
AsyncApexJob jobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob WHERE Id=:jobID];
Para encadenar procesos asíncronos de tipo Queueable solamente hemos de hacerlo dentro de nuestro execute:
public class AsyncExecutionExample implements Queueable { public void execute(QueueableContext context) { // Your processing logic here // Chain this job to next job by submitting the next job System.enqueueJob(new SecondJob()); // o quizás hacer una llamada recursiva a nosotros mismos } }
No olvidemos que debemos hacer Unit test a nuestro código con lo que como pasaba con @future , la llamada la haciemos entre las etiquetas Test.startTest()/ Test.stopTest() , en Queueable aún debemos seguir haciéndolo.
Quedaría de la siguiente manera:
@isTest public class AsyncExecutionExampleTest { static testmethod void test1() { // startTest/stopTest block to force async processes // to run in the test. Test.startTest(); ID jobID = System.enqueueJob(new AsyncExecutionExample()); Test.stopTest(); // Validate that the job has run AsyncApexJob jobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob WHERE Id=:jobID]; System.assertEquals('Completed', jobInfo.Status); System.assertEquals(0, jobInfo.NumberOfErrors); } }
Y para finalizar un pequeño ejemplo para hacer llamadas externas usando Queueable
public class MyQueueable implements Queueable,Database.AllowsCallouts { public void execute(QueueableContext context) { HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setHeader('Content-Type', 'application/json'); req.setEndPoint('https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=API_KEY'); req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId()); HttpResponse response = new Http().send(req); ID jobID = System.enqueueJob(new AsyncExecutionExample()); } }
Hemos visto lo que ganamos cuando usamos Queueable, pero cuales son sus limitaciones:
- Podemos encadenar solamente 2 procesos, no podemos encadenar hasta el “Infinito y más allá”
Entonces la siguiente pregunta sería cuando usar Queueable en lugar de Batch, pues bien, podríamos decir que usaremos Queueable cuando el volumen de registros a procesar sea mayor del permitido en un proceso síncrono pero sea proporcionalmente menor que el tamaño máximo de un proceso Batch, digamos para procesos asíncronos que solamente sean necesarios ejecutarse una vez o como máximo 2 , si no entonces necesitaremos implementar un proceso Batch. 🙂
Genial artículo Carolina!
Tengo una pregunta al respecto…mi idea es poder pasarle un método como parámetro para que cuando termine el proceso me avise, porque lo estoy esperando.
¿Habría otra forma de hacerlo?
Pasarle un método por parámetro? El nombre de un método quizás? o un objeto o clase? Bueno no estoy segura a lo que te refieres exactamente pero podrías pasarle cualquier cosa. Solamente tendrás que crear un constructor en la clase y desde ahi podrías inicializar todos los parámetros o variables que luego puedes usar en el execute 🙂
Ah! Otra cosa en Spring 15 ya se pueden encadenar más de 2