2

I was wondering if it is possible to call a batch from a @future method? The reason I am asking as you may have guessed is because I am trying to call batches from a trigger. Eg: Leads are inserted then call batch after insert trigger on Leads.

I know it is possible to call Database.executeBatch, however there is a limitation to the number of batches you can send. With current FlexQueue implementation you can invoke up to 100 batch calls per a transaction.

But my question is what if I need to send more than that per a transaction?

I was thinking of calling a @future method and in that method I call the batch, but I get this error:

System.AsyncException: Database.executeBatch cannot be called from a batch start, batch execute, or future method.

Pseudocode:

trigger leadTrigger on Lead(after insert) { 
    //some code 
    TriggerHelper.callTheBatch(); 
} 

public without sharing class TriggerHelper { 
    @future 
    public static void callTheBatch() { 
        MyBatchClass myBatchClass1 = new MyBatchClass(); 
        Id batchId = database.executebatch(myBatchClass1, 50); 
    } 
} 

Any suggestion or idea?

1 Answer 1

5

There's a number of ways to exceed 100 callouts per transaction using asynchronous code, but trying to call a batch from a future method doesn't even make sense, given all the sanctioned ways we've been given to do so. Here's a few things you could do:

Use @future methods

Break up your lists into batches of about 50 or so, and every 50 callouts just call your future method. You need to use callout=true to allow callouts, like this:

@future(callout=true) public static void doCallouts(Id[] recordIds) {
    ...
}

Use Queueable classes

Break up your lists into batches of about 50 or so, and every 50 callouts just call a Queueable. It'd look like this:

System.enqueueJob(new CalloutQueueable(Id[] recordIds));

Use Batchable classes... Responsibly

Dan Appleman made mention of using a retryable mechanism, and I've built one personally. The general idea is that you create a custom object that stores details about each callout you want to perform asynchronously. Then, you set up a scheduler that runs hourly, checks to see if any new integrations need to be processed, and if so, kicks off the batchable process. You can adjust the scheduler to be as frequent as you'd like, but by allowing a bit of pooling of the requests before trying to process them results in more efficient use of system resources. Other systems may not be able to handle this type of batching though, so smaller/more frequent batches may be required.

5
  • thank you for your help. I just didn't get this part "and every 50 callouts just call your future method". You mean for every 50 record Id's ,call doCallouts ?
    – Masoud Az
    Commented Mar 2, 2016 at 21:06
  • @MasoudAz Just call your future method periodically. This will create different async transactions that each have their own 100 callout limit. You're limited to 50 future calls per transaction, so it's advised to batch them up into reasonable sizes.
    – sfdcfox
    Commented Mar 2, 2016 at 21:07
  • Appleman's 3rd edition replaced the scheduler approach with queueables; retained the concept of the custom object to hold asyncRequests; see Chapter 7
    – cropredy
    Commented Mar 2, 2016 at 21:14
  • @crop1645 I'm not surprised. Queueable is so much cleaner than the prior solution. I wish we'd had that a while ago. It's a shame we still can't chain Queueable classes that also perform callouts.
    – sfdcfox
    Commented Mar 2, 2016 at 21:21
  • right; his 3rd edition pattern addresses how to solve this
    – cropredy
    Commented Mar 2, 2016 at 21:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .