+ Start a Discussion
Will Jones 18Will Jones 18 

System.LimitException: Too many future calls: 51 (I believe my code is bulkified)

I am receiving the infamous "System.LimitException: Too many future calls: 51" based on a trigger in my contact object. I am not sure how to handle this as I thought I bulkifie my code and added the statement:

"IF(System.IsBatch() == false && System.isFuture() == false)"

What else could it be?
 
trigger PortalContact on Contact (after insert, after update) {

//prevents an infinite loop
if(Recursion.objectRecursion)
    return;
Recursion.objectRecursion = TRUE;

//Create list of contacts
List<contact> cont_list = [SELECT Id, Group_Name__c, FirstName, LastName, Email, Portal_Account__c FROM Contact WHERE Id IN: Trigger.newmap.keyset() AND Portal_Account__c = TRUE];

   for (Contact c : cont_list) {
       
       if(c.Portal_Account__c){  
       
           if(!Test.isRunningTest()){
               IF(System.IsBatch() == false && System.isFuture() == false){ 
                    MySforceHttpCallOut.putDataToRemote_Contact(c.id, c.Group_Name__c, c.FirstName, c.LastName, c.Email); //call a method with @future annotation
                    MySforceHttpCallOut.postDataToRemote_Contact(c.id, c.Group_Name__c, c.FirstName, c.LastName, c.Email);
               }
           }
       }
  }
    
    //process updates
    if (cont_list.isEmpty()==FALSE){
        database.update(cont_list);
    }  
    
}

 
SivaGSivaG
Hi,

The reason could be the @future method inside the FOR loop. Try moving outside the FOR loop.

Thanks
Kumar
KaranrajKaranraj
Hi Will - Try to bulkify your trigger code, instead of passing single contact information to your future method, pass list of contact so that you will make only one future method call in your trigger code, no matter how many records your processing.
 
trigger PortalContact on Contact (after insert, after update) {
List<contact> contactList =  new List<contact>();

//prevents an infinite loop
if(Recursion.objectRecursion)
    return;
Recursion.objectRecursion = TRUE;

//Create list of contacts
List<contact> cont_list = [SELECT Id, Group_Name__c, FirstName, LastName, Email, Portal_Account__c FROM Contact WHERE Id IN: Trigger.newmap.keyset() AND Portal_Account__c = TRUE];

   for (Contact c : cont_list) {
       if(c.Portal_Account__c){  
         contactList.add(c);
       }
  }
MySforceHttpCallOut.putDataToRemote_Contact(c);//call a method with @future annotation
 MySforceHttpCallOut.postDataToRemote_Contact(c);
    //process updates
    if (cont_list.isEmpty()==FALSE){
        database.update(cont_list);
    }  
    
}

Your future class method will look like this 
@Future
 public static void generateReport_future(List<contact> contactRecords)
 {
 //Add your business logic to handle
}



 
JayantJayant
Seems like the web service methods you are calling out expect only 1 Contact at a time, so you have 2 options -

1. Get the web service methods you are calling out modified to accept a list of Contacts and process them instead of a single Contact.

Or

2. Since you are making 2 call outs per Contact record, ensure that the batch size is always lesser than or equal to 25. So that you would only use 50 call outs per trigger invocation. All API tools provide a facility to set the batch size as well as you may set the batch size in a batch class written in Apex. Through UI, usually the batch size is 1.
JayantJayant
In case you choose option 1 above - Since future methods only accept primitives or collections of primitives as arguments, you may pass only a set of Contact Ids and then retrieve the data in future method itself for processing.
Will Jones 18Will Jones 18
Thanks for the responses. I've updated my trigger as below but now am having issues with my method as Jayant mentioned would happen. What is the best way to process the data in the future method. My goal is to turn it into a JSON string to send to an external URL
 
trigger PortalContact on Contact (after insert, after update) {
List<contact> contactList =  new List<contact>();

//prevents an infinite loop
if(Recursion.objectRecursion)
    return;
Recursion.objectRecursion = TRUE;

//Create list of contacts
List<contact> cont_list = [SELECT Id, Group_Name__c, FirstName, LastName, Email, Portal_Account__c FROM Contact WHERE Id IN: Trigger.newmap.keyset() AND Portal_Account__c = TRUE];

   for (Contact c : cont_list) {
       if(c.Venue_Portal_Account__c){  
         contactList.add(c);
       }
  }
MySforceHttpCallOut.putDataToRemote_Contact(contactList);//call a method with @future annotation
 MySforceHttpCallOut.postDataToRemote_Contact(contactList);
    //process updates
    if (cont_list.isEmpty()==FALSE){
        database.update(cont_list);
    }  
    
}

My method that needs adjustment:
 
@future(callout=true)
public static void postDataToRemote_Contact(String id, String sf_account_id, String first_name, String last_name, String email_address){
             
             
             
             //Prepare https req
             httpRequest req = new httpRequest();
             req.setEndpoint('https://www.google.com);
             req.setHeader('Content-Type', 'application/json');
             req.setMethod('POST');
             req.setCompressed(false);
            
            //Build JSON String to send    
            String JSONString = '{\"sf_user_id\":\"' + id +'\",\"sf_account_id\":\"' + sf_account_id +'\",\"first_name\":\"' 
                + first_name +'\",\"last_name\":\"' + last_name +'\",\"email_address\":\"' + email_address +'\"}';
            System.debug('JSONString: ' + JSONString); //make sure format is correct
        
            
            req.setBody(JSONString);
     
            
            http http = new http();
            httpResponse res = http.send(req);
            
            System.debug(res.getBody());
        
  }

 
Will Jones 18Will Jones 18
Also with my future method, how do I send multiple records in the JSONString to the URL?