How to call Future methods from Batch?
Yes you heard it/seen it right, we cannot make call to the future methods directly from the batch, if you do then, the batch will fail with error that you cannot make call to the future methods from Batch.
00:03:41:690 EXCEPTION_THROWN [41]|System.AsyncException: Future method cannot be called from a future or batch method: MyClassSendingDataToExternalApplication.sendDataToThirdParty(Set<Id>)
But you still want to achieve this, so what are you going to do about it.
So here’s an alternative way of bypassing this issue and making call to this Future method. So here are the steps that need to be performed and then you should be able to make call to the future methods indirectly.
- When you are in batch class, In the execute method, you can call the Queueable class execute method.
- In the Queuable class, we have execute method there you call the future method
So with this way you can make the call to future method from Batch class
Lets get to the code. Here’s the boiler plate of the batch class.
/**
* @description MyClassSendingDataToExternalApplication to send data to other application
* To execute the batch following syntax to be used.
* MyClassSendingDataToExternalApplication bc = new MyClassSendingDataToExternalApplication('SuperAccount');
* Database.executeBatch (bc, 100);
*/
public class MyClassSendingDataToExternalApplication implements Database.Batchable<sObject> {
public String someProperty;
public MyClassSendingDataToExternalApplication(String props)
{
this.someProperty = props;
}
public Database.QueryLocator start(Database.BatchableContext bc)
{
String query = 'SELECT ID, Name FROM Account WHERE Name = :someProperty';
return Database.getQueryLocator(query);
}
public void execute(Database.BatchableContext bc, List<Account> accList)
{
Set<Id> accIds = (new map<Id,String> (accList)).keyset();
//Initiating the queue from Batch using SYSTEM.enqueueJob method
QueueSendSendDataService queueData = new QueueSendSendDataService(accIds);
System.enqueueJob(queueData);
}
public void finish(Database.BatchableContext bc)
{
//AnyReporting that we want to do
}
}
Now in the Queuable class you need to write something like this below where you can call the Future method in the execute method of this class.
/**
* This Class is a queueable class implementing the System.Queueable Interface
* To execute the class Use the below syntax
* QueueSendSendDataService queueData = new QueueSendSendDataService(accIds);
* System.enqueueJob(queueData);
*/
public class QueueSendSendDataService Implements System.Queueable {
Set<Id> accountIdSet = new Set<Id>();
public QueueSendSendDataService(Set<Id> accIdSet)
{
accountIdSet = accIdSet;
}
public void execute(QueueableContext qc)
{
//Call this future method which is declared in some other class.
FutureMethodClass.sendDataToExternalApp(accountIdSet);
}
}
This way you can now make call to the future methods even though you are not allowed to call the future methods from the batch class.
Note:
- When calling the Queueable class, it has 50 queues that can run in parallel, if this is exhausted then you cannot execute more queues until these are executed first.
- The chunk size of the Batch need to be taken more so that the more data can be passed to the queue thereby reducing the load of data that need to be cleanup from the batches.
I hope this post give some insights on the topic where many gets falter how this can be achieved.