function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Sumant KuchipudiSumant Kuchipudi 

Getting "Future method cannot be called from a future or batch method" error

Hi,
I have a trigger that invokes UpdateCallToExternal (future method), this external class checks for System.isFuture() and enqueJob with another class, and that another class invokes the future method in UpdateCallToExternal. Below is the code snippet.
 
global class UpdateCallToExternal {
    private static Integer callCount=0;

    @InvocableMethod
    global static void updateDeliveryStatus(List<Id> recIds){
        if(System.isFuture()){
            System.enqueueJob(new UpdateCallToExternalQueuable(String.join(recIds,',')));
        }else{
            invokeBulkUpdate(String.join(recIds,','));
        }

    }
    
    @future(callout=true)
    global static void invokeExternalSystem(String recIds){
        HttpRequest muleRequest = new HttpRequest();
        .....
    }

    global static void invokeBulkUpdate(String recIds) {
        callCount+=1;
        try {
            invokeExternalSystem(recIds);

         } catch(Exception e) {
             if (callCount <= 5)
                 invokeBulkUpdate(recIds);
         } 
    }
Below is Queuable class that invokes UpdateCallToExternal (future callout)
 
public class UpdateCallToExternalQueuable implements Queueable,Database.AllowsCallouts{
    String recIds;
    public UpdateCallToExternalQueuable(String recIds){
        this.recIds = recIds;
    }
    public void execute(QueueableContext qc){
        UpdateCallToExternal.invokeBulkUpdate(recIds);
    }
}

No idea what's wrong in this, could someone review the code and let me know the issue?
fyi: this error is raising exaclty raising at 10:00 PM only, no other timings.
 
VinayVinay (Salesforce Developers) 
Salesforce doesn't allow a future method to be called from another future method or a batch job. Before calling your future method, you should check if a future or batch job is already running. 

Eg:
if(System.IsBatch() == false && System.isFuture() == false){ 
    // make your future call here 
}

Thanks,
Sumant KuchipudiSumant Kuchipudi
Thanks @Vinay for your reply.
I'm already checking with System.isFuture(), if true, invoking queable class (UpdateCallToExternalQueuable).
if(System.isFuture()){
            System.enqueueJob(new UpdateCallToExternalQueuable(String.join(recIds,',')));
        }else{
            invokeBulkUpdate(String.join(recIds,','));
        }
So do I have to add the System.IsBatch() condition to the if condition?
 
if(System.isFuture() || System.isBatch()){
            System.enqueueJob(new UpdateCallToExternalQueuable(String.join(recIds,',')));
        }else{
            invokeBulkUpdate(String.join(recIds,','));
        }